summaryrefslogtreecommitdiff
path: root/includes/htmlform
diff options
context:
space:
mode:
Diffstat (limited to 'includes/htmlform')
-rw-r--r--includes/htmlform/HTMLCheckField.php46
-rw-r--r--includes/htmlform/HTMLCheckMatrix.php14
-rw-r--r--includes/htmlform/HTMLFloatField.php2
-rw-r--r--includes/htmlform/HTMLForm.php191
-rw-r--r--includes/htmlform/HTMLFormField.php50
-rw-r--r--includes/htmlform/HTMLFormFieldCloner.php42
-rw-r--r--includes/htmlform/HTMLHiddenField.php18
-rw-r--r--includes/htmlform/HTMLIntField.php5
-rw-r--r--includes/htmlform/HTMLMultiSelectField.php8
-rw-r--r--includes/htmlform/HTMLRadioField.php2
-rw-r--r--includes/htmlform/HTMLSelectAndOtherField.php11
-rw-r--r--includes/htmlform/HTMLSelectNamespace.php18
-rw-r--r--includes/htmlform/HTMLTagFilter.php31
-rw-r--r--includes/htmlform/HTMLTextField.php7
-rw-r--r--includes/htmlform/VFormHTMLForm.php141
15 files changed, 427 insertions, 159 deletions
diff --git a/includes/htmlform/HTMLCheckField.php b/includes/htmlform/HTMLCheckField.php
index 5f70362a..4942327f 100644
--- a/includes/htmlform/HTMLCheckField.php
+++ b/includes/htmlform/HTMLCheckField.php
@@ -20,28 +20,19 @@ class HTMLCheckField extends HTMLFormField {
$attr['class'] = $this->mClass;
}
- if ( $this->mParent->isVForm() ) {
- // Nest checkbox inside label.
- return Html::rawElement( 'label',
- array(
- 'class' => 'mw-ui-checkbox-label'
- ),
- Xml::check( $this->mName, $value, $attr ) . $this->mLabel );
- } else {
- $chkLabel = Xml::check( $this->mName, $value, $attr )
- . ' '
- . Html::rawElement( 'label', array( 'for' => $this->mID ), $this->mLabel );
-
- if ( $wgUseMediaWikiUIEverywhere ) {
- $chkLabel = Html::rawElement(
- 'div',
- array( 'class' => 'mw-ui-checkbox' ),
- $chkLabel
- );
- }
+ $chkLabel = Xml::check( $this->mName, $value, $attr )
+ . ' '
+ . Html::rawElement( 'label', array( 'for' => $this->mID ), $this->mLabel );
- return $chkLabel;
+ if ( $wgUseMediaWikiUIEverywhere || $this->mParent instanceof VFormHTMLForm ) {
+ $chkLabel = Html::rawElement(
+ 'div',
+ array( 'class' => 'mw-ui-checkbox' ),
+ $chkLabel
+ );
}
+
+ return $chkLabel;
}
/**
@@ -67,23 +58,16 @@ class HTMLCheckField extends HTMLFormField {
* @return string
*/
function loadDataFromRequest( $request ) {
- $invert = false;
- if ( isset( $this->mParams['invert'] ) && $this->mParams['invert'] ) {
- $invert = true;
- }
+ $invert = isset( $this->mParams['invert'] ) && $this->mParams['invert'];
// GetCheck won't work like we want for checks.
// Fetch the value in either one of the two following case:
// - we have a valid token (form got posted or GET forged by the user)
// - checkbox name has a value (false or true), ie is not null
if ( $request->getCheck( 'wpEditToken' ) || $request->getVal( $this->mName ) !== null ) {
- // XOR has the following truth table, which is what we want
- // INVERT VALUE | OUTPUT
- // true true | false
- // false true | true
- // false false | false
- // true false | true
- return $request->getBool( $this->mName ) xor $invert;
+ return $invert
+ ? !$request->getBool( $this->mName )
+ : $request->getBool( $this->mName );
} else {
return $this->getDefault();
}
diff --git a/includes/htmlform/HTMLCheckMatrix.php b/includes/htmlform/HTMLCheckMatrix.php
index 6c538fdd..83f12665 100644
--- a/includes/htmlform/HTMLCheckMatrix.php
+++ b/includes/htmlform/HTMLCheckMatrix.php
@@ -178,6 +178,13 @@ class HTMLCheckMatrix extends HTMLFormField implements HTMLNestedFilterable {
$helptext = $this->getHelpTextHtmlTable( $this->getHelpText() );
$cellAttributes = array( 'colspan' => 2 );
+ $hideClass = '';
+ $hideAttributes = array();
+ if ( $this->mHideIf ) {
+ $hideAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf );
+ $hideClass = 'mw-htmlform-hide-if';
+ }
+
$label = $this->getLabelHtml( $cellAttributes );
$field = Html::rawElement(
@@ -186,9 +193,12 @@ class HTMLCheckMatrix extends HTMLFormField implements HTMLNestedFilterable {
$inputHtml . "\n$errors"
);
- $html = Html::rawElement( 'tr', array( 'class' => 'mw-htmlform-vertical-label' ), $label );
+ $html = Html::rawElement( 'tr',
+ array( 'class' => "mw-htmlform-vertical-label $hideClass" ) + $hideAttributes,
+ $label );
$html .= Html::rawElement( 'tr',
- array( 'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass" ),
+ array( 'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass $hideClass" ) +
+ $hideAttributes,
$field );
return $html . $helptext;
diff --git a/includes/htmlform/HTMLFloatField.php b/includes/htmlform/HTMLFloatField.php
index 3b38fbe8..2ef49789 100644
--- a/includes/htmlform/HTMLFloatField.php
+++ b/includes/htmlform/HTMLFloatField.php
@@ -17,7 +17,7 @@ class HTMLFloatField extends HTMLTextField {
$value = trim( $value );
- # http://dev.w3.org/html5/spec/common-microsyntaxes.html#real-numbers
+ # http://www.w3.org/TR/html5/infrastructure.html#floating-point-numbers
# with the addition that a leading '+' sign is ok.
if ( !preg_match( '/^((\+|\-)?\d+(\.\d+)?(E(\+|\-)?\d+)?)?$/i', $value ) ) {
return $this->msg( 'htmlform-float-invalid' )->parseAsBlock();
diff --git a/includes/htmlform/HTMLForm.php b/includes/htmlform/HTMLForm.php
index d582da3b..ce140038 100644
--- a/includes/htmlform/HTMLForm.php
+++ b/includes/htmlform/HTMLForm.php
@@ -115,6 +115,8 @@ class HTMLForm extends ContextSource {
'info' => 'HTMLInfoField',
'selectorother' => 'HTMLSelectOrOtherField',
'selectandother' => 'HTMLSelectAndOtherField',
+ 'namespaceselect' => 'HTMLSelectNamespace',
+ 'tagfilter' => 'HTMLTagFilter',
'submit' => 'HTMLSubmitField',
'hidden' => 'HTMLHiddenField',
'edittools' => 'HTMLEditTools',
@@ -205,10 +207,42 @@ class HTMLForm extends ContextSource {
'table',
'div',
'raw',
+ 'inline',
+ );
+
+ /**
+ * Available formats in which to display the form
+ * @var array
+ */
+ protected $availableSubclassDisplayFormats = array(
'vform',
);
/**
+ * 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
+ */
+ public static function factory( $displayFormat/*, $arguments...*/ ) {
+ $arguments = func_get_args();
+ array_shift( $arguments );
+
+ switch ( $displayFormat ) {
+ case 'vform':
+ $reflector = new ReflectionClass( 'VFormHTMLForm' );
+ return $reflector->newInstanceArgs( $arguments );
+ default:
+ $reflector = new ReflectionClass( 'HTMLForm' );
+ $form = $reflector->newInstanceArgs( $arguments );
+ $form->setDisplayFormat( $displayFormat );
+ return $form;
+ }
+ }
+
+ /**
* Build a new HTMLForm from an array of field attributes
*
* @param array $descriptor Array of Field constructs, as described above
@@ -231,6 +265,11 @@ class HTMLForm extends ContextSource {
$this->mMessagePrefix = $context;
}
+ // Evil hack for mobile :(
+ if ( !$this->getConfig()->get( 'HTMLFormAllowTableFormat' ) && $this->displayFormat === 'table' ) {
+ $this->displayFormat = 'div';
+ }
+
// Expand out into a tree.
$loadedDescriptor = array();
$this->mFlatFields = array();
@@ -244,15 +283,7 @@ class HTMLForm extends ContextSource {
$this->mUseMultipart = true;
}
- $field = self::loadInputFromParameters( $fieldname, $info );
- // FIXME During field's construct, the parent form isn't available!
- // could add a 'parent' name-value to $info, could add a third parameter.
- $field->mParent = $this;
-
- // vform gets too much space if empty labels generate HTML.
- if ( $this->isVForm() ) {
- $field->setShowEmptyLabel( false );
- }
+ $field = static::loadInputFromParameters( $fieldname, $info, $this );
$setSection =& $loadedDescriptor;
if ( $section ) {
@@ -287,10 +318,24 @@ class HTMLForm extends ContextSource {
* @return HTMLForm $this for chaining calls (since 1.20)
*/
public function setDisplayFormat( $format ) {
+ if (
+ in_array( $format, $this->availableSubclassDisplayFormats ) ||
+ in_array( $this->displayFormat, $this->availableSubclassDisplayFormats )
+ ) {
+ throw new MWException( 'Cannot change display format after creation, ' .
+ 'use HTMLForm::factory() instead' );
+ }
+
if ( !in_array( $format, $this->availableDisplayFormats ) ) {
throw new MWException( 'Display format must be one of ' .
print_r( $this->availableDisplayFormats, true ) );
}
+
+ // Evil hack for mobile :(
+ if ( !$this->getConfig()->get( 'HTMLFormAllowTableFormat' ) && $format === 'table' ) {
+ $format = 'div';
+ }
+
$this->displayFormat = $format;
return $this;
@@ -302,20 +347,18 @@ class HTMLForm extends ContextSource {
* @return string
*/
public function getDisplayFormat() {
- $format = $this->displayFormat;
- if ( !$this->getConfig()->get( 'HTMLFormAllowTableFormat' ) && $format === 'table' ) {
- $format = 'div';
- }
- return $format;
+ return $this->displayFormat;
}
/**
* Test if displayFormat is 'vform'
* @since 1.22
+ * @deprecated since 1.25
* @return bool
*/
public function isVForm() {
- return $this->displayFormat === 'vform';
+ wfDeprecated( __METHOD__, '1.25' );
+ return false;
}
/**
@@ -338,7 +381,7 @@ class HTMLForm extends ContextSource {
if ( isset( $descriptor['class'] ) ) {
$class = $descriptor['class'];
} elseif ( isset( $descriptor['type'] ) ) {
- $class = self::$typeMappings[$descriptor['type']];
+ $class = static::$typeMappings[$descriptor['type']];
$descriptor['class'] = $class;
} else {
$class = null;
@@ -357,14 +400,18 @@ class HTMLForm extends ContextSource {
*
* @param string $fieldname Name of the field
* @param array $descriptor Input Descriptor, as described above
+ * @param HTMLForm|null $parent Parent instance of HTMLForm
*
* @throws MWException
* @return HTMLFormField Instance of a subclass of HTMLFormField
*/
- public static function loadInputFromParameters( $fieldname, $descriptor ) {
- $class = self::getClassFromDescriptor( $fieldname, $descriptor );
+ public static function loadInputFromParameters( $fieldname, $descriptor, HTMLForm $parent = null ) {
+ $class = static::getClassFromDescriptor( $fieldname, $descriptor );
$descriptor['fieldname'] = $fieldname;
+ if ( $parent ) {
+ $descriptor['parent'] = $parent;
+ }
# @todo This will throw a fatal error whenever someone try to use
# 'class' to feed a CSS class instead of 'cssclass'. Would be
@@ -787,14 +834,6 @@ class HTMLForm extends ContextSource {
# For good measure (it is the default)
$this->getOutput()->preventClickjacking();
$this->getOutput()->addModules( 'mediawiki.htmlform' );
- if ( $this->isVForm() ) {
- $this->getOutput()->addModuleStyles( array(
- 'mediawiki.ui',
- 'mediawiki.ui.button',
- ) );
- // @todo Should vertical form set setWrapperLegend( false )
- // to hide ugly fieldsets?
- }
$html = ''
. $this->getErrors( $submitResult )
@@ -810,18 +849,10 @@ class HTMLForm extends ContextSource {
}
/**
- * Wrap the form innards in an actual "<form>" element
- *
- * @param string $html HTML contents to wrap.
- *
- * @return string Wrapped HTML.
+ * Get HTML attributes for the `<form>` tag.
+ * @return array
*/
- function wrapForm( $html ) {
-
- # Include a <fieldset> wrapper for style, if requested.
- if ( $this->mWrapperLegend !== false ) {
- $html = Xml::fieldset( $this->mWrapperLegend, $html );
- }
+ protected function getFormAttributes() {
# Use multipart/form-data
$encType = $this->mUseMultipart
? 'multipart/form-data'
@@ -836,12 +867,23 @@ class HTMLForm extends ContextSource {
if ( !empty( $this->mId ) ) {
$attribs['id'] = $this->mId;
}
+ return $attribs;
+ }
- if ( $this->isVForm() ) {
- array_push( $attribs['class'], 'mw-ui-vform', 'mw-ui-container' );
+ /**
+ * Wrap the form innards in an actual "<form>" element
+ *
+ * @param string $html HTML contents to wrap.
+ *
+ * @return string Wrapped HTML.
+ */
+ function wrapForm( $html ) {
+ # Include a <fieldset> wrapper for style, if requested.
+ if ( $this->mWrapperLegend !== false ) {
+ $html = Xml::fieldset( $this->mWrapperLegend, $html );
}
- return Html::rawElement( 'form', $attribs, $html );
+ return Html::rawElement( 'form', $this->getFormAttributes(), $html );
}
/**
@@ -897,21 +939,10 @@ class HTMLForm extends ContextSource {
$attribs['class'] = array( 'mw-htmlform-submit' );
- if ( $this->isVForm() || $useMediaWikiUIEverywhere ) {
+ if ( $useMediaWikiUIEverywhere ) {
array_push( $attribs['class'], 'mw-ui-button', $this->mSubmitModifierClass );
}
- if ( $this->isVForm() ) {
- // mw-ui-block is necessary because the buttons aren't necessarily in an
- // immediate child div of the vform.
- // @todo Let client specify if the primary submit button is progressive or destructive
- array_push(
- $attribs['class'],
- 'mw-ui-big',
- 'mw-ui-block'
- );
- }
-
$buttons .= Xml::submitButton( $this->getSubmitText(), $attribs ) . "\n";
}
@@ -920,7 +951,8 @@ class HTMLForm extends ContextSource {
'input',
array(
'type' => 'reset',
- 'value' => $this->msg( 'htmlform-reset' )->text()
+ 'value' => $this->msg( 'htmlform-reset' )->text(),
+ 'class' => ( $useMediaWikiUIEverywhere ? 'mw-ui-button' : null ),
)
) . "\n";
}
@@ -940,15 +972,9 @@ class HTMLForm extends ContextSource {
$attrs['id'] = $button['id'];
}
- if ( $this->isVForm() || $useMediaWikiUIEverywhere ) {
- if ( isset( $attrs['class'] ) ) {
- $attrs['class'] .= ' mw-ui-button';
- } else {
- $attrs['class'] = 'mw-ui-button';
- }
- if ( $this->isVForm() ) {
- $attrs['class'] .= ' mw-ui-big mw-ui-block';
- }
+ if ( $useMediaWikiUIEverywhere ) {
+ $attrs['class'] = isset( $attrs['class'] ) ? (array)$attrs['class'] : array();
+ $attrs['class'][] = 'mw-ui-button';
}
$buttons .= Html::element( 'input', $attrs ) . "\n";
@@ -957,13 +983,6 @@ class HTMLForm extends ContextSource {
$html = Html::rawElement( 'span',
array( 'class' => 'mw-htmlform-submit-buttons' ), "\n$buttons" ) . "\n";
- // Buttons are top-level form elements in table and div layouts,
- // but vform wants all elements inside divs to get spaced-out block
- // styling.
- if ( $this->mShowSubmit && $this->isVForm() ) {
- $html = Html::rawElement( 'div', null, "\n$html" ) . "\n";
- }
-
return $html;
}
@@ -1007,7 +1026,7 @@ class HTMLForm extends ContextSource {
*
* @return string HTML, a "<ul>" list of errors
*/
- public static function formatErrors( $errors ) {
+ public function formatErrors( $errors ) {
$errorstr = '';
foreach ( $errors as $error ) {
@@ -1021,7 +1040,7 @@ class HTMLForm extends ContextSource {
$errorstr .= Html::rawElement(
'li',
array(),
- wfMessage( $msg, $error )->parse()
+ $this->msg( $msg, $error )->parse()
);
}
@@ -1045,13 +1064,21 @@ class HTMLForm extends ContextSource {
/**
* Identify that the submit button in the form has a destructive action
- *
+ * @since 1.24
*/
public function setSubmitDestructive() {
$this->mSubmitModifierClass = 'mw-ui-destructive';
}
/**
+ * Identify that the submit button in the form has a progressive action
+ * @since 1.25
+ */
+ public function setSubmitProgressive() {
+ $this->mSubmitModifierClass = 'mw-ui-progressive';
+ }
+
+ /**
* Set the text for the submit button to a message
* @since 1.19
*
@@ -1268,20 +1295,8 @@ class HTMLForm extends ContextSource {
$subsectionHtml = '';
$hasLabel = false;
- switch ( $displayFormat ) {
- case 'table':
- $getFieldHtmlMethod = 'getTableRow';
- break;
- case 'vform':
- // Close enough to a div.
- $getFieldHtmlMethod = 'getDiv';
- break;
- case 'div':
- $getFieldHtmlMethod = 'getDiv';
- break;
- default:
- $getFieldHtmlMethod = 'get' . ucfirst( $displayFormat );
- }
+ // Conveniently, PHP method names are case-insensitive.
+ $getFieldHtmlMethod = $displayFormat == 'table' ? 'getTableRow' : ( 'get' . $displayFormat );
foreach ( $fields as $key => $value ) {
if ( $value instanceof HTMLFormField ) {
@@ -1353,7 +1368,9 @@ class HTMLForm extends ContextSource {
$html = Html::rawElement( 'table',
$attribs,
Html::rawElement( 'tbody', array(), "\n$html\n" ) ) . "\n";
- } elseif ( $displayFormat === 'div' || $displayFormat === 'vform' ) {
+ } elseif ( $displayFormat === 'inline' ) {
+ $html = Html::rawElement( 'span', $attribs, "\n$html\n" );
+ } else {
$html = Html::rawElement( 'div', $attribs, "\n$html\n" );
}
}
diff --git a/includes/htmlform/HTMLFormField.php b/includes/htmlform/HTMLFormField.php
index 4cf23942..9576c77c 100644
--- a/includes/htmlform/HTMLFormField.php
+++ b/includes/htmlform/HTMLFormField.php
@@ -13,6 +13,7 @@ abstract class HTMLFormField {
protected $mLabel; # String label. Set on construction
protected $mID;
protected $mClass = '';
+ protected $mVFormClass = '';
protected $mHelpClass = false;
protected $mDefault;
protected $mOptions = false;
@@ -126,6 +127,7 @@ abstract class HTMLFormField {
* @param array $alldata
* @param array $params
* @return bool
+ * @throws MWException
*/
protected function isHiddenRecurse( array $alldata, array $params ) {
$origParams = $params;
@@ -217,7 +219,7 @@ abstract class HTMLFormField {
default:
throw new MWException( "Unknown operation" );
}
- } catch ( MWException $ex ) {
+ } catch ( Exception $ex ) {
throw new MWException(
"Invalid hide-if specification for $this->mName: " .
$ex->getMessage() . " in " . var_export( $origParams, true ),
@@ -343,6 +345,10 @@ abstract class HTMLFormField {
function __construct( $params ) {
$this->mParams = $params;
+ if ( isset( $params['parent'] ) && $params['parent'] instanceof HTMLForm ) {
+ $this->mParent = $params['parent'];
+ }
+
# Generate the label from a message, if possible
if ( isset( $params['label-message'] ) ) {
$msgInfo = $params['label-message'];
@@ -354,7 +360,7 @@ abstract class HTMLFormField {
$msgInfo = array();
}
- $this->mLabel = wfMessage( $msg, $msgInfo )->parse();
+ $this->mLabel = $this->msg( $msg, $msgInfo )->parse();
} elseif ( isset( $params['label'] ) ) {
if ( $params['label'] === '&#160;' ) {
// Apparently some things set &nbsp directly and in an odd format
@@ -507,10 +513,7 @@ abstract class HTMLFormField {
array( 'class' => $outerDivClass ) + $cellAttributes,
$inputHtml . "\n$errors"
);
- $divCssClasses = array( "mw-htmlform-field-$fieldType", $this->mClass, $errorClass );
- if ( $this->mParent->isVForm() ) {
- $divCssClasses[] = 'mw-ui-vform-field';
- }
+ $divCssClasses = array( "mw-htmlform-field-$fieldType", $this->mClass, $this->mVFormClass, $errorClass );
$wrapperAttributes = array(
'class' => $divCssClasses,
@@ -550,6 +553,41 @@ abstract class HTMLFormField {
}
/**
+ * Get the complete field for the input, including help text,
+ * labels, and whatever. Fall back from 'vform' to 'div' when not overridden.
+ *
+ * @since 1.25
+ * @param string $value The value to set the input to.
+ * @return string Complete HTML field.
+ */
+ public function getVForm( $value ) {
+ // Ewwww
+ $this->mVFormClass = ' mw-ui-vform-field';
+ return $this->getDiv( $value );
+ }
+
+ /**
+ * Get the complete field as an inline element.
+ * @since 1.25
+ * @param string $value The value to set the input to.
+ * @return string Complete HTML inline element
+ */
+ public function getInline( $value ) {
+ list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
+ $inputHtml = $this->getInputHTML( $value );
+ $helptext = $this->getHelpTextHtmlDiv( $this->getHelpText() );
+ $cellAttributes = array();
+ $label = $this->getLabelHtml( $cellAttributes );
+
+ $html = "\n" . $errors .
+ $label . '&#160;' .
+ $inputHtml .
+ $helptext;
+
+ return $html;
+ }
+
+ /**
* Generate help text HTML in table format
* @since 1.20
*
diff --git a/includes/htmlform/HTMLFormFieldCloner.php b/includes/htmlform/HTMLFormFieldCloner.php
index 029911cd..b06f10d5 100644
--- a/includes/htmlform/HTMLFormFieldCloner.php
+++ b/includes/htmlform/HTMLFormFieldCloner.php
@@ -96,8 +96,7 @@ class HTMLFormFieldCloner extends HTMLFormField {
} else {
$info['id'] = Sanitizer::escapeId( "{$this->mID}--$key--$fieldname" );
}
- $field = HTMLForm::loadInputFromParameters( $name, $info );
- $field->mParent = $this->mParent;
+ $field = HTMLForm::loadInputFromParameters( $name, $info, $this->mParent );
$fields[$fieldname] = $field;
}
return $fields;
@@ -263,19 +262,11 @@ class HTMLFormFieldCloner extends HTMLFormField {
? $this->mParams['format']
: $this->mParent->getDisplayFormat();
- switch ( $displayFormat ) {
- case 'table':
- $getFieldHtmlMethod = 'getTableRow';
- break;
- case 'vform':
- // Close enough to a div.
- $getFieldHtmlMethod = 'getDiv';
- break;
- default:
- $getFieldHtmlMethod = 'get' . ucfirst( $displayFormat );
- }
+ // Conveniently, PHP method names are case-insensitive.
+ $getFieldHtmlMethod = $displayFormat == 'table' ? 'getTableRow' : ( 'get' . $displayFormat );
$html = '';
+ $hidden = '';
$hasLabel = false;
$fields = $this->createFieldsForKey( $key );
@@ -283,11 +274,18 @@ class HTMLFormFieldCloner extends HTMLFormField {
$v = ( empty( $field->mParams['nodata'] ) && $values !== null )
? $values[$fieldname]
: $field->getDefault();
- $html .= $field->$getFieldHtmlMethod( $v );
- $labelValue = trim( $field->getLabel() );
- if ( $labelValue != '&#160;' && $labelValue !== '' ) {
- $hasLabel = true;
+ if ( $field instanceof HTMLHiddenField ) {
+ // HTMLHiddenField doesn't generate its own HTML
+ list( $name, $value, $params ) = $field->getHiddenFieldData( $v );
+ $hidden .= Html::hidden( $name, $value, $params ) . "\n";
+ } else {
+ $html .= $field->$getFieldHtmlMethod( $v );
+
+ $labelValue = trim( $field->getLabel() );
+ if ( $labelValue != '&#160;' && $labelValue !== '' ) {
+ $hasLabel = true;
+ }
}
}
@@ -302,8 +300,7 @@ class HTMLFormFieldCloner extends HTMLFormField {
'id' => Sanitizer::escapeId( "{$this->mID}--$key--delete" ),
'cssclass' => 'mw-htmlform-cloner-delete-button',
'default' => $this->msg( $label )->text(),
- ) );
- $field->mParent = $this->mParent;
+ ), $this->mParent );
$v = $field->getDefault();
if ( $displayFormat === 'table' ) {
@@ -330,11 +327,13 @@ class HTMLFormFieldCloner extends HTMLFormField {
$html = Html::rawElement( 'table',
$attribs,
Html::rawElement( 'tbody', array(), "\n$html\n" ) ) . "\n";
- } elseif ( $displayFormat === 'div' || $displayFormat === 'vform' ) {
+ } else {
$html = Html::rawElement( 'div', $attribs, "\n$html\n" );
}
}
+ $html .= $hidden;
+
if ( !empty( $this->mParams['row-legend'] ) ) {
$legend = $this->msg( $this->mParams['row-legend'] )->text();
$html = Xml::fieldset( $legend, $html );
@@ -373,8 +372,7 @@ class HTMLFormFieldCloner extends HTMLFormField {
'id' => Sanitizer::escapeId( "{$this->mID}--create" ),
'cssclass' => 'mw-htmlform-cloner-create-button',
'default' => $this->msg( $label )->text(),
- ) );
- $field->mParent = $this->mParent;
+ ), $this->mParent );
$html .= $field->getInputHTML( $field->getDefault() );
return $html;
diff --git a/includes/htmlform/HTMLHiddenField.php b/includes/htmlform/HTMLHiddenField.php
index e32c0bb2..ffde9151 100644
--- a/includes/htmlform/HTMLHiddenField.php
+++ b/includes/htmlform/HTMLHiddenField.php
@@ -1,22 +1,36 @@
<?php
class HTMLHiddenField extends HTMLFormField {
+ protected $outputAsDefault = true;
+
public function __construct( $params ) {
parent::__construct( $params );
+ if ( isset( $this->mParams['output-as-default'] ) ) {
+ $this->outputAsDefault = (bool)$this->mParams['output-as-default'];
+ }
+
# Per HTML5 spec, hidden fields cannot be 'required'
# http://www.w3.org/TR/html5/forms.html#hidden-state-%28type=hidden%29
unset( $this->mParams['required'] );
}
- public function getTableRow( $value ) {
+ public function getHiddenFieldData( $value ) {
$params = array();
if ( $this->mID ) {
$params['id'] = $this->mID;
}
- $this->mParent->addHiddenField( $this->mName, $this->mDefault, $params );
+ if ( $this->outputAsDefault ) {
+ $value = $this->mDefault;
+ }
+
+ return array( $this->mName, $value, $params );
+ }
+ public function getTableRow( $value ) {
+ list( $name, $value, $params ) = $this->getHiddenFieldData( $value );
+ $this->mParent->addHiddenField( $name, $value, $params );
return '';
}
diff --git a/includes/htmlform/HTMLIntField.php b/includes/htmlform/HTMLIntField.php
index 28876e2c..b0148d98 100644
--- a/includes/htmlform/HTMLIntField.php
+++ b/includes/htmlform/HTMLIntField.php
@@ -11,14 +11,13 @@ class HTMLIntField extends HTMLFloatField {
return $p;
}
- # http://dev.w3.org/html5/spec/common-microsyntaxes.html#signed-integers
+ # http://www.w3.org/TR/html5/infrastructure.html#signed-integers
# with the addition that a leading '+' sign is ok. Note that leading zeros
# are fine, and will be left in the input, which is useful for things like
# phone numbers when you know that they are integers (the HTML5 type=tel
# input does not require its value to be numeric). If you want a tidier
# value to, eg, save in the DB, clean it up with intval().
- if ( !preg_match( '/^((\+|\-)?\d+)?$/', trim( $value ) )
- ) {
+ if ( !preg_match( '/^((\+|\-)?\d+)?$/', trim( $value ) ) ) {
return $this->msg( 'htmlform-int-invalid' )->parseAsBlock();
}
diff --git a/includes/htmlform/HTMLMultiSelectField.php b/includes/htmlform/HTMLMultiSelectField.php
index 1b71ab95..8d28b59e 100644
--- a/includes/htmlform/HTMLMultiSelectField.php
+++ b/includes/htmlform/HTMLMultiSelectField.php
@@ -59,6 +59,14 @@ class HTMLMultiSelectField extends HTMLFormField implements HTMLNestedFilterable
$label
);
+ if ( $this->mParent->getConfig()->get( 'UseMediaWikiUIEverywhere' ) ) {
+ $checkbox = Html::rawElement(
+ 'div',
+ array( 'class' => 'mw-ui-checkbox' ),
+ $checkbox
+ );
+ }
+
$html .= ' ' . Html::rawElement(
'div',
array( 'class' => 'mw-htmlform-flatlist-item' ),
diff --git a/includes/htmlform/HTMLRadioField.php b/includes/htmlform/HTMLRadioField.php
index 8765407b..0f005408 100644
--- a/includes/htmlform/HTMLRadioField.php
+++ b/includes/htmlform/HTMLRadioField.php
@@ -56,7 +56,7 @@ class HTMLRadioField extends HTMLFormField {
$html .= ' ' . Html::rawElement(
'div',
- array( 'class' => 'mw-htmlform-flatlist-item' ),
+ array( 'class' => 'mw-htmlform-flatlist-item mw-ui-radio' ),
$radio
);
}
diff --git a/includes/htmlform/HTMLSelectAndOtherField.php b/includes/htmlform/HTMLSelectAndOtherField.php
index 65176dd7..a1c0c957 100644
--- a/includes/htmlform/HTMLSelectAndOtherField.php
+++ b/includes/htmlform/HTMLSelectAndOtherField.php
@@ -13,6 +13,7 @@
class HTMLSelectAndOtherField extends HTMLSelectField {
function __construct( $params ) {
if ( array_key_exists( 'other', $params ) ) {
+ // Do nothing
} elseif ( array_key_exists( 'other-message', $params ) ) {
$params['other'] = wfMessage( $params['other-message'] )->plain();
} else {
@@ -22,7 +23,7 @@ class HTMLSelectAndOtherField extends HTMLSelectField {
parent::__construct( $params );
if ( $this->getOptions() === null ) {
- # Sulk
+ // Sulk
throw new MWException( 'HTMLSelectAndOtherField called without any options' );
}
if ( !in_array( 'other', $this->mOptions, true ) ) {
@@ -39,10 +40,12 @@ class HTMLSelectAndOtherField extends HTMLSelectField {
$textAttribs = array(
'id' => $this->mID . '-other',
'size' => $this->getSize(),
+ 'class' => array( 'mw-htmlform-select-and-other-field' ),
+ 'data-id-select' => $this->mID,
);
if ( $this->mClass !== '' ) {
- $textAttribs['class'] = $this->mClass;
+ $textAttribs['class'][] = $this->mClass;
}
$allowedParams = array(
@@ -50,7 +53,8 @@ class HTMLSelectAndOtherField extends HTMLSelectField {
'autofocus',
'multiple',
'disabled',
- 'tabindex'
+ 'tabindex',
+ 'maxlength', // gets dynamic with javascript, see mediawiki.htmlform.js
);
$textAttribs += $this->getAttributes( $allowedParams );
@@ -71,6 +75,7 @@ class HTMLSelectAndOtherField extends HTMLSelectField {
$list = $request->getText( $this->mName );
$text = $request->getText( $this->mName . '-other' );
+ // Should be built the same as in mediawiki.htmlform.js
if ( $list == 'other' ) {
$final = $text;
} elseif ( !in_array( $list, $this->mFlatOptions, true ) ) {
diff --git a/includes/htmlform/HTMLSelectNamespace.php b/includes/htmlform/HTMLSelectNamespace.php
new file mode 100644
index 00000000..96381062
--- /dev/null
+++ b/includes/htmlform/HTMLSelectNamespace.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Wrapper for Html::namespaceSelector to use in HTMLForm
+ */
+class HTMLSelectNamespace extends HTMLFormField {
+ function getInputHTML( $value ) {
+ return Html::namespaceSelector(
+ array(
+ 'selected' => $value,
+ 'all' => 'all'
+ ), array(
+ 'name' => $this->mName,
+ 'id' => $this->mID,
+ 'class' => 'namespaceselector',
+ )
+ );
+ }
+}
diff --git a/includes/htmlform/HTMLTagFilter.php b/includes/htmlform/HTMLTagFilter.php
new file mode 100644
index 00000000..8075de5a
--- /dev/null
+++ b/includes/htmlform/HTMLTagFilter.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Wrapper for ChangeTags::buildTagFilterSelector to use in HTMLForm
+ */
+class HTMLTagFilter extends HTMLFormField {
+ protected $tagFilter;
+
+ function getTableRow( $value ) {
+ $this->tagFilter = ChangeTags::buildTagFilterSelector( $value );
+ if ( $this->tagFilter ) {
+ return parent::getTableRow( $value );
+ }
+ return '';
+ }
+
+ function getDiv( $value ) {
+ $this->tagFilter = ChangeTags::buildTagFilterSelector( $value );
+ if ( $this->tagFilter ) {
+ return parent::getDiv( $value );
+ }
+ return '';
+ }
+
+ function getInputHTML( $value ) {
+ if ( $this->tagFilter ) {
+ // we only need the select field, HTMLForm should handle the label
+ return $this->tagFilter[1];
+ }
+ return '';
+ }
+}
diff --git a/includes/htmlform/HTMLTextField.php b/includes/htmlform/HTMLTextField.php
index 10bc67f0..88df49db 100644
--- a/includes/htmlform/HTMLTextField.php
+++ b/includes/htmlform/HTMLTextField.php
@@ -20,6 +20,7 @@ class HTMLTextField extends HTMLFormField {
# @todo Enforce pattern, step, required, readonly on the server side as
# well
$allowedParams = array(
+ 'type',
'min',
'max',
'pattern',
@@ -38,10 +39,13 @@ class HTMLTextField extends HTMLFormField {
$attribs += $this->getAttributes( $allowedParams );
+ # Extract 'type'
+ $type = isset( $attribs['type'] ) ? $attribs['type'] : 'text';
+ unset( $attribs['type'] );
+
# Implement tiny differences between some field variants
# here, rather than creating a new class for each one which
# is essentially just a clone of this one.
- $type = 'text';
if ( isset( $this->mParams['type'] ) ) {
switch ( $this->mParams['type'] ) {
case 'int':
@@ -60,6 +64,7 @@ class HTMLTextField extends HTMLFormField {
break;
}
}
+
return Html::input( $this->mName, $value, $type, $attribs );
}
}
diff --git a/includes/htmlform/VFormHTMLForm.php b/includes/htmlform/VFormHTMLForm.php
new file mode 100644
index 00000000..0c0e4252
--- /dev/null
+++ b/includes/htmlform/VFormHTMLForm.php
@@ -0,0 +1,141 @@
+<?php
+
+/**
+ * HTML form generation and submission handling, vertical-form style.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * Compact stacked vertical format for forms.
+ */
+class VFormHTMLForm extends HTMLForm {
+ /**
+ * Wrapper and its legend are never generated in VForm mode.
+ * @var boolean
+ */
+ protected $mWrapperLegend = false;
+
+ /**
+ * Symbolic display format name.
+ * @var string
+ */
+ protected $displayFormat = 'vform';
+
+ public function isVForm() {
+ wfDeprecated( __METHOD__, '1.25' );
+ return true;
+ }
+
+ public static function loadInputFromParameters( $fieldname, $descriptor, HTMLForm $parent = null ) {
+ $field = parent::loadInputFromParameters( $fieldname, $descriptor, $parent );
+ $field->setShowEmptyLabel( false );
+ return $field;
+ }
+
+ function getHTML( $submitResult ) {
+ // This is required for VForm HTMLForms that use that style regardless
+ // of wgUseMediaWikiUIEverywhere (since they pre-date it).
+ // When wgUseMediaWikiUIEverywhere is removed, this should be consolidated
+ // with the addModuleStyles in SpecialPage->setHeaders.
+ $this->getOutput()->addModuleStyles( array(
+ 'mediawiki.ui',
+ 'mediawiki.ui.button',
+ 'mediawiki.ui.input',
+ 'mediawiki.ui.checkbox',
+ ) );
+
+ return parent::getHTML( $submitResult );
+ }
+
+ protected function getFormAttributes() {
+ $attribs = parent::getFormAttributes();
+ array_push( $attribs['class'], 'mw-ui-vform', 'mw-ui-container' );
+ return $attribs;
+ }
+
+ function wrapForm( $html ) {
+ // Always discard $this->mWrapperLegend
+ return Html::rawElement( 'form', $this->getFormAttributes(), $html );
+ }
+
+ function getButtons() {
+ $buttons = '';
+
+ if ( $this->mShowSubmit ) {
+ $attribs = array();
+
+ if ( isset( $this->mSubmitID ) ) {
+ $attribs['id'] = $this->mSubmitID;
+ }
+
+ if ( isset( $this->mSubmitName ) ) {
+ $attribs['name'] = $this->mSubmitName;
+ }
+
+ if ( isset( $this->mSubmitTooltip ) ) {
+ $attribs += Linker::tooltipAndAccesskeyAttribs( $this->mSubmitTooltip );
+ }
+
+ $attribs['class'] = array(
+ 'mw-htmlform-submit',
+ 'mw-ui-button mw-ui-big mw-ui-block',
+ $this->mSubmitModifierClass,
+ );
+
+ $buttons .= Xml::submitButton( $this->getSubmitText(), $attribs ) . "\n";
+ }
+
+ if ( $this->mShowReset ) {
+ $buttons .= Html::element(
+ 'input',
+ array(
+ 'type' => 'reset',
+ 'value' => $this->msg( 'htmlform-reset' )->text(),
+ 'class' => 'mw-ui-button mw-ui-big mw-ui-block',
+ )
+ ) . "\n";
+ }
+
+ foreach ( $this->mButtons as $button ) {
+ $attrs = array(
+ 'type' => 'submit',
+ 'name' => $button['name'],
+ 'value' => $button['value']
+ );
+
+ if ( $button['attribs'] ) {
+ $attrs += $button['attribs'];
+ }
+
+ if ( isset( $button['id'] ) ) {
+ $attrs['id'] = $button['id'];
+ }
+
+ $attrs['class'] = isset( $attrs['class'] ) ? (array)$attrs['class'] : array();
+ $attrs['class'][] = 'mw-ui-button mw-ui-big mw-ui-block';
+
+ $buttons .= Html::element( 'input', $attrs ) . "\n";
+ }
+
+ $html = Html::rawElement( 'div',
+ array( 'class' => 'mw-htmlform-submit-buttons' ), "\n$buttons" ) . "\n";
+
+ return $html;
+ }
+}