'UsersPager' => __DIR__ . '/includes/specials/SpecialListusers.php',
'UtfNormal' => __DIR__ . '/includes/normal/UtfNormal.php',
'UzConverter' => __DIR__ . '/languages/classes/LanguageUz.php',
+ 'VFormHTMLForm' => __DIR__ . '/includes/htmlform/VFormHTMLForm.php',
'ValidateRegistrationFile' => __DIR__ . '/maintenance/validateRegistrationFile.php',
'ViewAction' => __DIR__ . '/includes/actions/ViewAction.php',
'VirtualRESTService' => __DIR__ . '/includes/libs/virtualrest/VirtualRESTService.php',
$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;
}
/**
'table',
'div',
'raw',
+ );
+
+ /**
+ * 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
*
$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();
$this->mUseMultipart = true;
}
- $field = self::loadInputFromParameters( $fieldname, $info, $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 ) {
* @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;
* @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';
+ return false;
}
/**
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;
* @return HTMLFormField Instance of a subclass of HTMLFormField
*/
public static function loadInputFromParameters( $fieldname, $descriptor, HTMLForm $parent = null ) {
- $class = self::getClassFromDescriptor( $fieldname, $descriptor );
+ $class = static::getClassFromDescriptor( $fieldname, $descriptor );
$descriptor['fieldname'] = $fieldname;
if ( $parent ) {
# For good measure (it is the default)
$this->getOutput()->preventClickjacking();
$this->getOutput()->addModules( 'mediawiki.htmlform' );
- if ( $this->isVForm() ) {
- // 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',
- ) );
- // @todo Should vertical form set setWrapperLegend( false )
- // to hide ugly fieldsets?
- }
$html = ''
. $this->getErrors( $submitResult )
}
/**
- * 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'
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 );
}
/**
$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";
}
'input',
array(
'type' => 'reset',
- 'value' => $this->msg( 'htmlform-reset' )->text()
+ 'value' => $this->msg( 'htmlform-reset' )->text(),
+ 'class' => ( $useMediaWikiUIEverywhere ? 'mw-ui-button' : null ),
)
) . "\n";
}
$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";
$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;
}
$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 ) {
$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" );
}
}
$inputHtml . "\n$errors"
);
$divCssClasses = array( "mw-htmlform-field-$fieldType", $this->mClass, $errorClass );
- if ( $this->mParent->isVForm() ) {
- $divCssClasses[] = 'mw-ui-vform-field';
- }
$wrapperAttributes = array(
'class' => $divCssClasses,
return $html;
}
+ /**
+ * 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->mClass .= ' mw-ui-vform-field';
+ return $this->getDiv( $value );
+ }
+
/**
* Generate help text HTML in table format
* @since 1.20
? $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 = '';
$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" );
}
}
--- /dev/null
+<?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() {
+ 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;
+ }
+}
return strtolower( $this->getName() );
}
+ /**
+ * Get display format for the form. See HTMLForm documentation for available values.
+ *
+ * @since 1.25
+ * @return string
+ */
+ protected function getDisplayFormat() {
+ return 'table';
+ }
+
/**
* Get the HTMLForm to control behavior
* @return HTMLForm|null
protected function getForm() {
$this->fields = $this->getFormFields();
- $form = new HTMLForm( $this->fields, $this->getContext(), $this->getMessagePrefix() );
+ $form = HTMLForm::factory( $this->getDisplayFormat(), $this->fields, $this->getContext(), $this->getMessagePrefix() );
$form->setSubmitCallback( array( $this, 'onSubmit' ) );
- // If the form is a compact vertical form, then don't output this ugly
- // fieldset surrounding it.
- // XXX Special pages can setDisplayFormat to 'vform' in alterForm(), but that
- // is called after this.
- if ( !$form->isVForm() ) {
- $form->setWrapperLegendMsg( $this->getMessagePrefix() . '-legend' );
- }
+ $form->setWrapperLegendMsg( $this->getMessagePrefix() . '-legend' );
$headerMsg = $this->msg( $this->getMessagePrefix() . '-text' );
if ( !$headerMsg->isDisabled() ) {
return $fields;
}
+ protected function getDisplayFormat() {
+ return 'vform';
+ }
+
protected function alterForm( HTMLForm $form ) {
- $form->setDisplayFormat( 'vform' );
$form->setId( 'mw-changeemail-form' );
$form->setTableId( 'mw-changeemail-table' );
- $form->setWrapperLegend( false );
$form->setSubmitTextMsg( 'changeemail-submit' );
$form->addHiddenFields( $this->getRequest()->getValues( 'returnto', 'returntoquery' ) );
}
return $this->showLogFragment( $this->par );
}
+ protected function getDisplayFormat() {
+ return 'vform';
+ }
+
public function alterForm( HTMLForm $form ) {
- $form->setDisplayFormat( 'vform' );
- $form->setWrapperLegend( false );
Hooks::run( 'LanguageSelector', array( $this->getOutput(), 'mw-languageselector' ) );
}
return $a;
}
+ protected function getDisplayFormat() {
+ return 'vform';
+ }
+
public function alterForm( HTMLForm $form ) {
$resetRoutes = $this->getConfig()->get( 'PasswordResetRoutes' );
- $form->setDisplayFormat( 'vform' );
- // Turn the old-school line around the form off.
- // XXX This wouldn't be necessary here if we could set the format of
- // the HTMLForm to 'vform' at its creation, but there's no way to do so
- // from a FormSpecialPage class.
- $form->setWrapperLegend( false );
-
$form->addHiddenFields( $this->getRequest()->getValues( 'returnto', 'returntoquery' ) );
$i = 0;