2009-04-24 01:31:17 +00:00
|
|
|
<?php
|
2012-05-14 17:59:58 +00:00
|
|
|
/**
|
|
|
|
|
* HTML form generation and submission handling.
|
|
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
|
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
2010-05-30 12:44:17 +00:00
|
|
|
* Object handling generic submission, CSRF protection, layout and
|
|
|
|
|
* other logic for UI forms. in a reusable manner.
|
2009-09-28 19:04:10 +00:00
|
|
|
*
|
2010-05-30 12:44:17 +00:00
|
|
|
* In order to generate the form, the HTMLForm object takes an array
|
|
|
|
|
* structure detailing the form fields available. Each element of the
|
|
|
|
|
* array is a basic property-list, including the type of field, the
|
2009-09-28 19:04:10 +00:00
|
|
|
* label it is to be given in the form, callbacks for validation and
|
2010-05-30 12:44:17 +00:00
|
|
|
* 'filtering', and other pertinent information.
|
2009-09-28 19:04:10 +00:00
|
|
|
*
|
|
|
|
|
* Field types are implemented as subclasses of the generic HTMLFormField
|
2010-05-30 12:44:17 +00:00
|
|
|
* object, and typically implement at least getInputHTML, which generates
|
2009-09-28 19:04:10 +00:00
|
|
|
* the HTML for the input field to be placed in the table.
|
2010-05-30 12:44:17 +00:00
|
|
|
*
|
2012-08-02 16:26:08 +00:00
|
|
|
* You can find extensive documentation on the www.mediawiki.org wiki:
|
|
|
|
|
* - http://www.mediawiki.org/wiki/HTMLForm
|
|
|
|
|
* - http://www.mediawiki.org/wiki/HTMLForm/tutorial
|
|
|
|
|
*
|
2009-09-28 19:04:10 +00:00
|
|
|
* The constructor input is an associative array of $fieldname => $info,
|
|
|
|
|
* where $info is an Associative Array with any of the following:
|
2010-05-30 12:44:17 +00:00
|
|
|
*
|
2010-12-12 15:32:29 +00:00
|
|
|
* 'class' -- the subclass of HTMLFormField that will be used
|
|
|
|
|
* to create the object. *NOT* the CSS class!
|
|
|
|
|
* 'type' -- roughly translates into the <select> 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
|
|
|
|
|
* '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
|
|
|
|
|
* the message.
|
|
|
|
|
* 'label' -- alternatively, a raw text message. Overridden by
|
|
|
|
|
* label-message
|
2012-03-06 15:36:08 +00:00
|
|
|
* 'help' -- message text for a message to use as a help text.
|
2010-12-12 15:32:29 +00:00
|
|
|
* 'help-message' -- message key for a message to use as a help text.
|
|
|
|
|
* can be an array of msg key and then parameters to
|
|
|
|
|
* the message.
|
2012-03-06 15:36:08 +00:00
|
|
|
* Overwrites 'help-messages' and 'help'.
|
2011-10-26 20:58:29 +00:00
|
|
|
* 'help-messages' -- array of message key. As above, each item can
|
|
|
|
|
* be an array of msg key and then parameters.
|
2012-03-06 15:36:08 +00:00
|
|
|
* Overwrites 'help'.
|
2010-12-12 15:32:29 +00:00
|
|
|
* 'required' -- passed through to the object, indicating that it
|
|
|
|
|
* is a required field.
|
|
|
|
|
* '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()
|
|
|
|
|
* 'validation-callback' -- a function name to give you the chance
|
|
|
|
|
* to impose extra validation on the field input.
|
|
|
|
|
* @see HTMLForm::validate()
|
2010-12-15 21:37:50 +00:00
|
|
|
* '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.
|
2010-05-30 12:44:17 +00:00
|
|
|
*
|
2012-07-24 09:45:22 +00:00
|
|
|
* Since 1.20, you can chain mutators to ease the form generation:
|
|
|
|
|
* @par Example:
|
|
|
|
|
* @code
|
|
|
|
|
* $form = new HTMLForm( $someFields );
|
|
|
|
|
* $form->setMethod( 'get' )
|
|
|
|
|
* ->setWrapperLegendMsg( 'message-key' )
|
|
|
|
|
* ->prepareForm()
|
2013-04-22 18:20:41 +00:00
|
|
|
* ->displayForm( '' );
|
2012-07-24 09:45:22 +00:00
|
|
|
* @endcode
|
|
|
|
|
* Note that you will have prepareForm and displayForm at the end. Other
|
|
|
|
|
* methods call done after that would simply not be part of the form :(
|
|
|
|
|
*
|
2009-09-28 19:04:10 +00:00
|
|
|
* TODO: Document 'section' / 'subsection' stuff
|
|
|
|
|
*/
|
2011-10-23 18:09:44 +00:00
|
|
|
class HTMLForm extends ContextSource {
|
2009-04-24 01:31:17 +00:00
|
|
|
|
2012-01-13 22:19:01 +00:00
|
|
|
// A mapping of 'type' inputs onto standard HTMLFormField subclasses
|
2013-03-26 23:17:17 +00:00
|
|
|
private static $typeMappings = array(
|
2012-12-07 07:22:10 +00:00
|
|
|
'api' => 'HTMLApiField',
|
2009-06-21 18:26:29 +00:00
|
|
|
'text' => 'HTMLTextField',
|
2009-10-09 14:22:37 +00:00
|
|
|
'textarea' => 'HTMLTextAreaField',
|
2009-06-21 18:26:29 +00:00
|
|
|
'select' => 'HTMLSelectField',
|
|
|
|
|
'radio' => 'HTMLRadioField',
|
|
|
|
|
'multiselect' => 'HTMLMultiSelectField',
|
|
|
|
|
'check' => 'HTMLCheckField',
|
|
|
|
|
'toggle' => 'HTMLCheckField',
|
|
|
|
|
'int' => 'HTMLIntField',
|
2009-07-17 22:19:02 +00:00
|
|
|
'float' => 'HTMLFloatField',
|
2009-06-21 18:26:29 +00:00
|
|
|
'info' => 'HTMLInfoField',
|
|
|
|
|
'selectorother' => 'HTMLSelectOrOtherField',
|
2011-03-05 16:51:13 +00:00
|
|
|
'selectandother' => 'HTMLSelectAndOtherField',
|
2009-09-28 19:04:10 +00:00
|
|
|
'submit' => 'HTMLSubmitField',
|
|
|
|
|
'hidden' => 'HTMLHiddenField',
|
2009-10-18 19:29:35 +00:00
|
|
|
'edittools' => 'HTMLEditTools',
|
2013-02-14 02:05:13 +00:00
|
|
|
'checkmatrix' => 'HTMLCheckMatrix',
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2012-01-13 22:19:01 +00:00
|
|
|
// HTMLTextField will output the correct type="" attribute automagically.
|
|
|
|
|
// There are about four zillion other HTML5 input types, like url, but
|
|
|
|
|
// we don't use those at the moment, so no point in adding all of them.
|
Start using some HTML 5 form features
autofocus attribute added in some places; this looks like it's respected
by both recent Opera and recent WebKit. Its function is
self-explanatory. :) I used this in a few obvious places like
Special:UserLogin and Special:ResetPass to focus the first field in the
form. Could be used in other places too: Special:Search, etc.
required attribute added in some places. This is only supported in
recent Opera at the moment. Also self-explanatory: it won't allow form
submission if the field is empty.
For stuff using HTMLForm (i.e., Special:Preferences), validation will be
done for integers and floats. Browsers that support this (recent Opera)
will not allow non-integers to be submitted for integer fields, will not
allow non-floating-point values to be submitted for float fields, and
will enforce any min/max values specified. Opera also gives little up
and down arrows to allow the user to increment/decrement the value in
addition to letting them edit the field as text.
For HTMLForm and account creation, the email input type is used for
e-mails. This enforces a sane set of values for e-mails (alphanumerics
plus some ASCII punctuation, with an @ in it). Again, this is supported
only by recent Opera (yay Opera!). Note that this is actually more
restrictive than what we currently check for on the server side; it
might be sane to tighten up our server-side checks to forbid e-mail
addresses that HTML 5 forbids.
In all cases, the extra features aren't added if $wgHtml5 is false, and
will be ignored by non-supporting browsers.
The major room for further improvement here is use of the pattern
attribute. We can have the client refuse to submit the form unless it
matches a regex! The HTML 5 spec says that if a title attribute is
provided, it should be a message that explains what the valid values
are and browsers should provide it to the user if the regex doesn't
match, so it's not a usability problem. I didn't bother adding that
anywhere at this point because it would require adding new messages, but
it should be easy to do. Note of course that HTMLForm should be updated
to verify that pattern matches on the server side as well -- this way we
have a clean, unified way of ensuring that our client and server checks
are the same.
2009-08-07 03:32:20 +00:00
|
|
|
'email' => 'HTMLTextField',
|
2009-09-06 15:41:24 +00:00
|
|
|
'password' => 'HTMLTextField',
|
2009-06-21 18:26:29 +00:00
|
|
|
);
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
protected $mMessagePrefix;
|
2011-10-17 15:56:25 +00:00
|
|
|
|
|
|
|
|
/** @var HTMLFormField[] */
|
2009-09-28 19:04:10 +00:00
|
|
|
protected $mFlatFields;
|
2011-10-17 15:56:25 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
protected $mFieldTree;
|
|
|
|
|
protected $mShowReset = false;
|
2013-03-09 01:30:49 +00:00
|
|
|
protected $mShowSubmit = true;
|
2009-09-28 19:04:10 +00:00
|
|
|
public $mFieldData;
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
protected $mSubmitCallback;
|
|
|
|
|
protected $mValidationErrorMessage;
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
protected $mPre = '';
|
|
|
|
|
protected $mHeader = '';
|
2010-04-10 21:10:22 +00:00
|
|
|
protected $mFooter = '';
|
2011-01-25 20:56:56 +00:00
|
|
|
protected $mSectionHeaders = array();
|
|
|
|
|
protected $mSectionFooters = array();
|
2009-09-28 19:04:10 +00:00
|
|
|
protected $mPost = '';
|
2009-10-18 19:29:35 +00:00
|
|
|
protected $mId;
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
protected $mSubmitID;
|
2009-10-18 19:29:35 +00:00
|
|
|
protected $mSubmitName;
|
2009-09-28 19:04:10 +00:00
|
|
|
protected $mSubmitText;
|
2009-10-18 19:29:35 +00:00
|
|
|
protected $mSubmitTooltip;
|
2011-04-13 16:51:22 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
protected $mTitle;
|
2010-12-15 19:33:03 +00:00
|
|
|
protected $mMethod = 'post';
|
2012-01-30 11:33:16 +00:00
|
|
|
|
2012-01-29 15:23:23 +00:00
|
|
|
/**
|
2012-01-30 11:33:16 +00:00
|
|
|
* Form action URL. false means we will use the URL to set Title
|
2012-01-29 15:23:23 +00:00
|
|
|
* @since 1.19
|
2012-02-09 17:42:35 +00:00
|
|
|
* @var bool|string
|
2012-01-29 15:23:23 +00:00
|
|
|
*/
|
|
|
|
|
protected $mAction = false;
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-10-18 19:29:35 +00:00
|
|
|
protected $mUseMultipart = false;
|
2009-09-28 19:04:10 +00:00
|
|
|
protected $mHiddenFields = array();
|
|
|
|
|
protected $mButtons = array();
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
protected $mWrapperLegend = false;
|
2012-05-04 22:09:33 +00:00
|
|
|
|
2011-10-31 14:41:02 +00:00
|
|
|
/**
|
|
|
|
|
* If true, sections that contain both fields and subsections will
|
|
|
|
|
* render their subsections before their fields.
|
2012-05-04 22:09:33 +00:00
|
|
|
*
|
2011-10-31 14:41:02 +00:00
|
|
|
* Subclasses may set this to false to render subsections after fields
|
|
|
|
|
* instead.
|
|
|
|
|
*/
|
|
|
|
|
protected $mSubSectionBeforeFields = true;
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2012-05-04 22:09:33 +00:00
|
|
|
/**
|
|
|
|
|
* Format in which to display form. For viable options,
|
|
|
|
|
* @see $availableDisplayFormats
|
|
|
|
|
* @var String
|
|
|
|
|
*/
|
|
|
|
|
protected $displayFormat = 'table';
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Available formats in which to display the form
|
|
|
|
|
* @var Array
|
|
|
|
|
*/
|
|
|
|
|
protected $availableDisplayFormats = array(
|
|
|
|
|
'table',
|
|
|
|
|
'div',
|
|
|
|
|
'raw',
|
|
|
|
|
);
|
|
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Build a new HTMLForm from an array of field attributes
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param array $descriptor of Field constructs, as described above
|
2011-09-15 15:19:49 +00:00
|
|
|
* @param $context IContextSource available since 1.18, will become compulsory in 1.18.
|
2011-04-13 16:51:22 +00:00
|
|
|
* Obviates the need to call $form->setTitle()
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $messagePrefix a prefix to go in front of default messages
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2011-09-15 15:19:49 +00:00
|
|
|
public function __construct( $descriptor, /*IContextSource*/ $context = null, $messagePrefix = '' ) {
|
2012-05-04 22:09:33 +00:00
|
|
|
if ( $context instanceof IContextSource ) {
|
2011-10-23 18:09:44 +00:00
|
|
|
$this->setContext( $context );
|
2011-04-13 16:51:22 +00:00
|
|
|
$this->mTitle = false; // We don't need them to set a title
|
|
|
|
|
$this->mMessagePrefix = $messagePrefix;
|
|
|
|
|
} else {
|
|
|
|
|
// B/C since 1.18
|
2012-05-04 22:09:33 +00:00
|
|
|
if ( is_string( $context ) && $messagePrefix === '' ) {
|
2011-04-13 16:51:22 +00:00
|
|
|
// it's actually $messagePrefix
|
|
|
|
|
$this->mMessagePrefix = $context;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
// Expand out into a tree.
|
|
|
|
|
$loadedDescriptor = array();
|
|
|
|
|
$this->mFlatFields = array();
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-05-30 12:44:17 +00:00
|
|
|
foreach ( $descriptor as $fieldname => $info ) {
|
|
|
|
|
$section = isset( $info['section'] )
|
2010-04-10 12:03:30 +00:00
|
|
|
? $info['section']
|
|
|
|
|
: '';
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( isset( $info['type'] ) && $info['type'] == 'file' ) {
|
2009-10-18 19:29:35 +00:00
|
|
|
$this->mUseMultipart = true;
|
2010-04-10 12:03:30 +00:00
|
|
|
}
|
2009-10-18 19:29:35 +00:00
|
|
|
|
2010-12-15 21:14:36 +00:00
|
|
|
$field = self::loadInputFromParameters( $fieldname, $info );
|
2009-04-24 01:31:17 +00:00
|
|
|
$field->mParent = $this;
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
$setSection =& $loadedDescriptor;
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( $section ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
$sectionParts = explode( '/', $section );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-05-30 12:44:17 +00:00
|
|
|
while ( count( $sectionParts ) ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
$newName = array_shift( $sectionParts );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
|
|
|
|
if ( !isset( $setSection[$newName] ) ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
$setSection[$newName] = array();
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
$setSection =& $setSection[$newName];
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
$setSection[$fieldname] = $field;
|
|
|
|
|
$this->mFlatFields[$fieldname] = $field;
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
$this->mFieldTree = $loadedDescriptor;
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2012-05-04 22:09:33 +00:00
|
|
|
/**
|
|
|
|
|
* Set format in which to display the form
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $format the name of the format to use, must be one of
|
2012-05-04 22:09:33 +00:00
|
|
|
* $this->availableDisplayFormats
|
2012-10-07 23:35:26 +00:00
|
|
|
* @throws MWException
|
2012-05-04 22:09:33 +00:00
|
|
|
* @since 1.20
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2012-05-04 22:09:33 +00:00
|
|
|
*/
|
|
|
|
|
public function setDisplayFormat( $format ) {
|
|
|
|
|
if ( !in_array( $format, $this->availableDisplayFormats ) ) {
|
2013-03-24 10:01:51 +00:00
|
|
|
throw new MWException( 'Display format must be one of ' . print_r( $this->availableDisplayFormats, true ) );
|
2012-05-04 22:09:33 +00:00
|
|
|
}
|
|
|
|
|
$this->displayFormat = $format;
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2012-05-04 22:09:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Getter for displayFormat
|
|
|
|
|
* @since 1.20
|
|
|
|
|
* @return String
|
|
|
|
|
*/
|
|
|
|
|
public function getDisplayFormat() {
|
|
|
|
|
return $this->displayFormat;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
2010-05-30 12:44:17 +00:00
|
|
|
* Add the HTMLForm-specific JavaScript, if it hasn't been
|
2009-09-28 19:04:10 +00:00
|
|
|
* done already.
|
2011-03-12 18:14:33 +00:00
|
|
|
* @deprecated since 1.18 load modules with ResourceLoader instead
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2013-04-20 22:49:30 +00:00
|
|
|
static function addJS() {
|
|
|
|
|
wfDeprecated( __METHOD__, '1.18' );
|
|
|
|
|
}
|
2009-04-24 01:31:17 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Initialise a new Object for the field
|
2011-08-02 23:16:44 +00:00
|
|
|
* @param $fieldname string
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $descriptor input Descriptor, as described above
|
2012-10-07 23:35:26 +00:00
|
|
|
* @throws MWException
|
2009-09-28 19:04:10 +00:00
|
|
|
* @return HTMLFormField subclass
|
|
|
|
|
*/
|
2010-12-15 21:14:36 +00:00
|
|
|
static function loadInputFromParameters( $fieldname, $descriptor ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
if ( isset( $descriptor['class'] ) ) {
|
|
|
|
|
$class = $descriptor['class'];
|
|
|
|
|
} elseif ( isset( $descriptor['type'] ) ) {
|
|
|
|
|
$class = self::$typeMappings[$descriptor['type']];
|
|
|
|
|
$descriptor['class'] = $class;
|
2011-04-13 16:51:22 +00:00
|
|
|
} else {
|
|
|
|
|
$class = null;
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( !$class ) {
|
2009-06-21 18:26:29 +00:00
|
|
|
throw new MWException( "Descriptor with no class: " . print_r( $descriptor, true ) );
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2011-03-05 12:48:32 +00:00
|
|
|
|
2010-12-15 21:14:36 +00:00
|
|
|
$descriptor['fieldname'] = $fieldname;
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2012-03-05 12:05:13 +00:00
|
|
|
# TODO
|
|
|
|
|
# This will throw a fatal error whenever someone try to use
|
|
|
|
|
# 'class' to feed a CSS class instead of 'cssclass'. Would be
|
|
|
|
|
# great to avoid the fatal error and show a nice error.
|
2009-04-24 01:31:17 +00:00
|
|
|
$obj = new $class( $descriptor );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
return $obj;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
2012-07-24 09:45:22 +00:00
|
|
|
* Prepare form for submission.
|
|
|
|
|
*
|
|
|
|
|
* @attention When doing method chaining, that should be the very last
|
|
|
|
|
* method call before displayForm().
|
|
|
|
|
*
|
2012-10-07 23:35:26 +00:00
|
|
|
* @throws MWException
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2010-12-15 01:17:28 +00:00
|
|
|
function prepareForm() {
|
2010-12-12 15:32:29 +00:00
|
|
|
# Check if we have the info we need
|
2011-04-13 16:51:22 +00:00
|
|
|
if ( !$this->mTitle instanceof Title && $this->mTitle !== false ) {
|
2010-05-03 09:10:50 +00:00
|
|
|
throw new MWException( "You must call setTitle() on an HTMLForm" );
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
# Load data from the request.
|
2009-04-24 01:31:17 +00:00
|
|
|
$this->loadData();
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2010-12-15 01:17:28 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-12-15 01:17:28 +00:00
|
|
|
/**
|
|
|
|
|
* Try submitting, with edit token check first
|
2011-03-05 12:48:32 +00:00
|
|
|
* @return Status|boolean
|
2010-12-15 01:17:28 +00:00
|
|
|
*/
|
|
|
|
|
function tryAuthorizedSubmit() {
|
2009-04-24 01:31:17 +00:00
|
|
|
$result = false;
|
2012-01-30 23:44:34 +00:00
|
|
|
|
|
|
|
|
$submit = false;
|
|
|
|
|
if ( $this->getMethod() != 'post' ) {
|
|
|
|
|
$submit = true; // no session check needed
|
|
|
|
|
} elseif ( $this->getRequest()->wasPosted() ) {
|
|
|
|
|
$editToken = $this->getRequest()->getVal( 'wpEditToken' );
|
|
|
|
|
if ( $this->getUser()->isLoggedIn() || $editToken != null ) {
|
|
|
|
|
// Session tokens for logged-out users have no security value.
|
2012-05-04 22:09:33 +00:00
|
|
|
// However, if the user gave one, check it in order to give a nice
|
2012-01-30 23:44:34 +00:00
|
|
|
// "session expired" error instead of "permission denied" or such.
|
|
|
|
|
$submit = $this->getUser()->matchEditToken( $editToken );
|
|
|
|
|
} else {
|
|
|
|
|
$submit = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( $submit ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
$result = $this->trySubmit();
|
2010-05-30 12:44:17 +00:00
|
|
|
}
|
2012-01-30 23:44:34 +00:00
|
|
|
|
2010-12-15 01:17:28 +00:00
|
|
|
return $result;
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-12-15 01:17:28 +00:00
|
|
|
/**
|
|
|
|
|
* The here's-one-I-made-earlier option: do the submission if
|
2012-03-21 23:07:06 +00:00
|
|
|
* posted, or display the form with or without funky validation
|
2010-12-15 01:17:28 +00:00
|
|
|
* errors
|
|
|
|
|
* @return Bool or Status whether submission was successful.
|
|
|
|
|
*/
|
|
|
|
|
function show() {
|
|
|
|
|
$this->prepareForm();
|
|
|
|
|
|
|
|
|
|
$result = $this->tryAuthorizedSubmit();
|
2012-03-21 23:07:06 +00:00
|
|
|
if ( $result === true || ( $result instanceof Status && $result->isGood() ) ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
return $result;
|
2010-05-30 12:44:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
$this->displayForm( $result );
|
2009-09-28 19:04:10 +00:00
|
|
|
return false;
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
2013-03-13 07:42:41 +00:00
|
|
|
* Validate all the fields, and call the submission callback
|
2009-09-28 19:04:10 +00:00
|
|
|
* function if everything is kosher.
|
2012-10-07 23:35:26 +00:00
|
|
|
* @throws MWException
|
2009-09-28 19:04:10 +00:00
|
|
|
* @return Mixed Bool true == Successful submission, Bool false
|
2012-10-07 23:35:26 +00:00
|
|
|
* == No submission attempted, anything else == Error to
|
|
|
|
|
* display.
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function trySubmit() {
|
2009-09-28 19:04:10 +00:00
|
|
|
# Check for validation
|
2010-05-30 12:44:17 +00:00
|
|
|
foreach ( $this->mFlatFields as $fieldname => $field ) {
|
|
|
|
|
if ( !empty( $field->mParams['nodata'] ) ) {
|
2009-09-28 19:04:10 +00:00
|
|
|
continue;
|
2010-04-10 12:03:30 +00:00
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( $field->validate(
|
2009-09-28 19:04:10 +00:00
|
|
|
$this->mFieldData[$fieldname],
|
2010-05-30 12:44:17 +00:00
|
|
|
$this->mFieldData )
|
|
|
|
|
!== true
|
|
|
|
|
) {
|
2009-09-28 19:04:10 +00:00
|
|
|
return isset( $this->mValidationErrorMessage )
|
|
|
|
|
? $this->mValidationErrorMessage
|
|
|
|
|
: array( 'htmlform-invalid-input' );
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
$callback = $this->mSubmitCallback;
|
2012-05-22 15:09:52 +00:00
|
|
|
if ( !is_callable( $callback ) ) {
|
|
|
|
|
throw new MWException( 'HTMLForm: no submit callback provided. Use setSubmitCallback() to set one.' );
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
$data = $this->filterDataForSubmit( $this->mFieldData );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2011-10-09 11:43:06 +00:00
|
|
|
$res = call_user_func( $callback, $data, $this );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
return $res;
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Set a callback to a function to do something with the form
|
|
|
|
|
* once it's been successfully validated.
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $cb function name. The function will be passed
|
2009-09-28 19:04:10 +00:00
|
|
|
* the output from HTMLForm::filterDataForSubmit, and must
|
|
|
|
|
* return Bool true on success, Bool false if no submission
|
|
|
|
|
* was attempted, or String HTML output to display on error.
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function setSubmitCallback( $cb ) {
|
|
|
|
|
$this->mSubmitCallback = $cb;
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
2010-05-30 12:44:17 +00:00
|
|
|
* Set a message to display on a validation error.
|
2012-08-19 20:44:29 +00:00
|
|
|
* @param $msg Mixed String or Array of valid inputs to wfMessage()
|
2009-09-28 19:04:10 +00:00
|
|
|
* (so each entry can be either a String or Array)
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function setValidationErrorMessage( $msg ) {
|
|
|
|
|
$this->mValidationErrorMessage = $msg;
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Set the introductory message, overwriting any existing message.
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $msg complete text of message to display
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2011-10-23 18:38:22 +00:00
|
|
|
function setIntro( $msg ) {
|
|
|
|
|
$this->setPreText( $msg );
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2011-10-23 18:38:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set the introductory message, overwriting any existing message.
|
|
|
|
|
* @since 1.19
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $msg complete text of message to display
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2011-10-23 18:38:22 +00:00
|
|
|
*/
|
2012-07-24 09:45:22 +00:00
|
|
|
function setPreText( $msg ) {
|
|
|
|
|
$this->mPre = $msg;
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Add introductory text.
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $msg complete text of message to display
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2012-07-24 09:45:22 +00:00
|
|
|
function addPreText( $msg ) {
|
|
|
|
|
$this->mPre .= $msg;
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Add header text, inside the form.
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $msg complete text of message to display
|
|
|
|
|
* @param string $section The section to add the header to
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2011-05-25 15:39:47 +00:00
|
|
|
function addHeaderText( $msg, $section = null ) {
|
2011-01-25 20:56:56 +00:00
|
|
|
if ( is_null( $section ) ) {
|
2011-05-25 15:39:47 +00:00
|
|
|
$this->mHeader .= $msg;
|
2011-01-25 20:56:56 +00:00
|
|
|
} else {
|
|
|
|
|
if ( !isset( $this->mSectionHeaders[$section] ) ) {
|
|
|
|
|
$this->mSectionHeaders[$section] = '';
|
|
|
|
|
}
|
|
|
|
|
$this->mSectionHeaders[$section] .= $msg;
|
|
|
|
|
}
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2011-01-25 20:56:56 +00:00
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2011-10-23 18:38:22 +00:00
|
|
|
/**
|
|
|
|
|
* Set header text, inside the form.
|
|
|
|
|
* @since 1.19
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $msg complete text of message to display
|
2011-10-23 18:38:22 +00:00
|
|
|
* @param $section The section to add the header to
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2011-10-23 18:38:22 +00:00
|
|
|
*/
|
|
|
|
|
function setHeaderText( $msg, $section = null ) {
|
|
|
|
|
if ( is_null( $section ) ) {
|
|
|
|
|
$this->mHeader = $msg;
|
|
|
|
|
} else {
|
|
|
|
|
$this->mSectionHeaders[$section] = $msg;
|
|
|
|
|
}
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2011-10-23 18:38:22 +00:00
|
|
|
}
|
|
|
|
|
|
2010-04-10 21:10:22 +00:00
|
|
|
/**
|
|
|
|
|
* Add footer text, inside the form.
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $msg complete text of message to display
|
|
|
|
|
* @param string $section The section to add the footer text to
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2010-04-10 21:10:22 +00:00
|
|
|
*/
|
2011-05-25 15:39:47 +00:00
|
|
|
function addFooterText( $msg, $section = null ) {
|
2011-01-25 20:56:56 +00:00
|
|
|
if ( is_null( $section ) ) {
|
2011-05-25 15:39:47 +00:00
|
|
|
$this->mFooter .= $msg;
|
2011-01-25 20:56:56 +00:00
|
|
|
} else {
|
|
|
|
|
if ( !isset( $this->mSectionFooters[$section] ) ) {
|
|
|
|
|
$this->mSectionFooters[$section] = '';
|
|
|
|
|
}
|
2011-05-25 15:39:47 +00:00
|
|
|
$this->mSectionFooters[$section] .= $msg;
|
2011-01-25 20:56:56 +00:00
|
|
|
}
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2011-01-25 20:56:56 +00:00
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2011-10-23 18:38:22 +00:00
|
|
|
/**
|
|
|
|
|
* Set footer text, inside the form.
|
|
|
|
|
* @since 1.19
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $msg complete text of message to display
|
|
|
|
|
* @param string $section The section to add the footer text to
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2011-10-23 18:38:22 +00:00
|
|
|
*/
|
|
|
|
|
function setFooterText( $msg, $section = null ) {
|
|
|
|
|
if ( is_null( $section ) ) {
|
|
|
|
|
$this->mFooter = $msg;
|
|
|
|
|
} else {
|
|
|
|
|
$this->mSectionFooters[$section] = $msg;
|
|
|
|
|
}
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2011-10-23 18:38:22 +00:00
|
|
|
}
|
|
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Add text to the end of the display.
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $msg complete text of message to display
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2012-07-24 09:45:22 +00:00
|
|
|
function addPostText( $msg ) {
|
|
|
|
|
$this->mPost .= $msg;
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2011-10-23 18:38:22 +00:00
|
|
|
/**
|
|
|
|
|
* Set text at the end of the display.
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $msg complete text of message to display
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2011-10-23 18:38:22 +00:00
|
|
|
*/
|
2012-07-24 09:45:22 +00:00
|
|
|
function setPostText( $msg ) {
|
|
|
|
|
$this->mPost = $msg;
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
2011-10-23 18:38:22 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Add a hidden field to the output
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $name field name. This will be used exactly as entered
|
|
|
|
|
* @param string $value field value
|
2010-04-10 12:03:30 +00:00
|
|
|
* @param $attribs Array
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2010-05-30 12:44:17 +00:00
|
|
|
public function addHiddenField( $name, $value, $attribs = array() ) {
|
2010-04-14 21:42:37 +00:00
|
|
|
$attribs += array( 'name' => $name );
|
|
|
|
|
$this->mHiddenFields[] = array( $value, $attribs );
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2009-09-28 19:04:10 +00:00
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2012-07-24 09:45:22 +00:00
|
|
|
/**
|
|
|
|
|
* Add a button to the form
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $name field name.
|
|
|
|
|
* @param string $value field value
|
|
|
|
|
* @param string $id DOM id for the button (default: null)
|
2012-07-24 09:45:22 +00:00
|
|
|
* @param $attribs Array
|
|
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
|
|
|
|
*/
|
2010-05-30 12:44:17 +00:00
|
|
|
public function addButton( $name, $value, $id = null, $attribs = null ) {
|
2009-10-18 19:29:35 +00:00
|
|
|
$this->mButtons[] = compact( 'name', 'value', 'id', 'attribs' );
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2009-09-22 20:05:28 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
2011-12-31 21:25:00 +00:00
|
|
|
* Display the form (sending to $wgOut), with an appropriate error
|
2009-09-28 19:04:10 +00:00
|
|
|
* message or stack of messages, and any validation errors, etc.
|
2012-07-24 09:45:22 +00:00
|
|
|
*
|
|
|
|
|
* @attention You should call prepareForm() before calling this function.
|
|
|
|
|
* Moreover, when doing method chaining this should be the very last method
|
|
|
|
|
* call just after prepareForm().
|
|
|
|
|
*
|
2009-09-28 19:04:10 +00:00
|
|
|
* @param $submitResult Mixed output from HTMLForm::trySubmit()
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return Nothing, should be last call
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function displayForm( $submitResult ) {
|
2011-10-08 19:13:35 +00:00
|
|
|
$this->getOutput()->addHTML( $this->getHTML( $submitResult ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the raw HTML generated by the form
|
|
|
|
|
* @param $submitResult Mixed output from HTMLForm::trySubmit()
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
function getHTML( $submitResult ) {
|
2011-01-04 06:12:33 +00:00
|
|
|
# For good measure (it is the default)
|
2011-04-13 16:51:22 +00:00
|
|
|
$this->getOutput()->preventClickjacking();
|
|
|
|
|
$this->getOutput()->addModules( 'mediawiki.htmlform' );
|
2011-01-04 06:12:33 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
$html = ''
|
2010-04-10 21:10:22 +00:00
|
|
|
. $this->getErrors( $submitResult )
|
2009-09-28 19:04:10 +00:00
|
|
|
. $this->mHeader
|
|
|
|
|
. $this->getBody()
|
|
|
|
|
. $this->getHiddenFields()
|
|
|
|
|
. $this->getButtons()
|
2010-04-10 21:10:22 +00:00
|
|
|
. $this->mFooter
|
2009-09-28 19:04:10 +00:00
|
|
|
;
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
$html = $this->wrapForm( $html );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2011-10-08 19:13:35 +00:00
|
|
|
return '' . $this->mPre . $html . $this->mPost;
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
2012-07-10 12:48:06 +00:00
|
|
|
* Wrap the form innards in an actual "<form>" element
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $html HTML contents to wrap.
|
2009-09-28 19:04:10 +00:00
|
|
|
* @return String wrapped HTML.
|
|
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function wrapForm( $html ) {
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
# Include a <fieldset> wrapper for style, if requested.
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( $this->mWrapperLegend !== false ) {
|
2009-09-28 19:04:10 +00:00
|
|
|
$html = Xml::fieldset( $this->mWrapperLegend, $html );
|
|
|
|
|
}
|
2009-10-18 19:29:35 +00:00
|
|
|
# Use multipart/form-data
|
2010-05-30 12:44:17 +00:00
|
|
|
$encType = $this->mUseMultipart
|
2009-10-18 19:29:35 +00:00
|
|
|
? 'multipart/form-data'
|
|
|
|
|
: 'application/x-www-form-urlencoded';
|
|
|
|
|
# Attributes
|
|
|
|
|
$attribs = array(
|
2013-02-03 20:05:24 +00:00
|
|
|
'action' => $this->mAction === false ? $this->getTitle()->getFullURL() : $this->mAction,
|
|
|
|
|
'method' => $this->mMethod,
|
|
|
|
|
'class' => 'visualClear',
|
2010-05-30 12:44:17 +00:00
|
|
|
'enctype' => $encType,
|
2009-06-21 18:26:29 +00:00
|
|
|
);
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( !empty( $this->mId ) ) {
|
2009-10-18 19:29:35 +00:00
|
|
|
$attribs['id'] = $this->mId;
|
2010-05-30 12:44:17 +00:00
|
|
|
}
|
|
|
|
|
|
2009-10-18 19:29:35 +00:00
|
|
|
return Html::rawElement( 'form', $attribs, $html );
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Get the hidden fields that should go inside the form.
|
|
|
|
|
* @return String HTML.
|
|
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function getHiddenFields() {
|
2012-03-24 08:25:01 +00:00
|
|
|
global $wgArticlePath;
|
2011-08-23 19:56:15 +00:00
|
|
|
|
2010-05-30 12:44:17 +00:00
|
|
|
$html = '';
|
2012-05-04 22:09:33 +00:00
|
|
|
if ( $this->getMethod() == 'post' ) {
|
2011-11-16 04:37:17 +00:00
|
|
|
$html .= Html::hidden( 'wpEditToken', $this->getUser()->getEditToken(), array( 'id' => 'wpEditToken' ) ) . "\n";
|
2010-12-15 21:37:50 +00:00
|
|
|
$html .= Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) . "\n";
|
|
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2012-03-24 08:25:01 +00:00
|
|
|
if ( strpos( $wgArticlePath, '?' ) !== false && $this->getMethod() == 'get' ) {
|
2011-08-23 19:56:15 +00:00
|
|
|
$html .= Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) . "\n";
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-30 12:44:17 +00:00
|
|
|
foreach ( $this->mHiddenFields as $data ) {
|
2010-04-14 21:42:37 +00:00
|
|
|
list( $value, $attribs ) = $data;
|
|
|
|
|
$html .= Html::hidden( $attribs['name'], $value, $attribs ) . "\n";
|
2009-09-28 19:04:10 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
return $html;
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Get the submit and (potentially) reset buttons.
|
|
|
|
|
* @return String HTML.
|
|
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function getButtons() {
|
|
|
|
|
$html = '';
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2013-03-09 01:30:49 +00:00
|
|
|
if ( $this->mShowSubmit ) {
|
|
|
|
|
$attribs = array();
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2013-03-09 01:30:49 +00:00
|
|
|
if ( isset( $this->mSubmitID ) ) {
|
|
|
|
|
$attribs['id'] = $this->mSubmitID;
|
|
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2013-03-09 01:30:49 +00:00
|
|
|
if ( isset( $this->mSubmitName ) ) {
|
|
|
|
|
$attribs['name'] = $this->mSubmitName;
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2013-03-09 01:30:49 +00:00
|
|
|
if ( isset( $this->mSubmitTooltip ) ) {
|
|
|
|
|
$attribs += Linker::tooltipAndAccesskeyAttribs( $this->mSubmitTooltip );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$attribs['class'] = 'mw-htmlform-submit';
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2013-03-09 01:30:49 +00:00
|
|
|
$html .= Xml::submitButton( $this->getSubmitText(), $attribs ) . "\n";
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( $this->mShowReset ) {
|
2009-09-07 01:47:45 +00:00
|
|
|
$html .= Html::element(
|
2009-06-21 18:26:29 +00:00
|
|
|
'input',
|
|
|
|
|
array(
|
|
|
|
|
'type' => 'reset',
|
2012-08-21 20:11:18 +00:00
|
|
|
'value' => $this->msg( 'htmlform-reset' )->text()
|
2009-06-21 18:26:29 +00:00
|
|
|
)
|
|
|
|
|
) . "\n";
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
|
|
|
|
foreach ( $this->mButtons as $button ) {
|
2009-09-28 19:04:10 +00:00
|
|
|
$attrs = array(
|
2013-02-03 20:05:24 +00:00
|
|
|
'type' => 'submit',
|
|
|
|
|
'name' => $button['name'],
|
2009-09-28 19:04:10 +00:00
|
|
|
'value' => $button['value']
|
|
|
|
|
);
|
2010-05-30 12:44:17 +00:00
|
|
|
|
|
|
|
|
if ( $button['attribs'] ) {
|
|
|
|
|
$attrs += $button['attribs'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( isset( $button['id'] ) ) {
|
2009-09-28 19:04:10 +00:00
|
|
|
$attrs['id'] = $button['id'];
|
2010-05-30 12:44:17 +00:00
|
|
|
}
|
|
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
$html .= Html::element( 'input', $attrs );
|
|
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
return $html;
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Get the whole body of the form.
|
2011-10-17 15:56:25 +00:00
|
|
|
* @return String
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function getBody() {
|
|
|
|
|
return $this->displaySection( $this->mFieldTree );
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Format and display an error message stack.
|
2011-04-23 21:27:24 +00:00
|
|
|
* @param $errors String|Array|Status
|
2010-04-10 21:10:22 +00:00
|
|
|
* @return String
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2010-04-10 21:10:22 +00:00
|
|
|
function getErrors( $errors ) {
|
2010-12-03 11:29:55 +00:00
|
|
|
if ( $errors instanceof Status ) {
|
2011-02-02 15:44:42 +00:00
|
|
|
if ( $errors->isOK() ) {
|
|
|
|
|
$errorstr = '';
|
|
|
|
|
} else {
|
2011-04-13 16:51:22 +00:00
|
|
|
$errorstr = $this->getOutput()->parse( $errors->getWikiText() );
|
2011-02-02 15:44:42 +00:00
|
|
|
}
|
2010-12-03 11:29:55 +00:00
|
|
|
} elseif ( is_array( $errors ) ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
$errorstr = $this->formatErrors( $errors );
|
|
|
|
|
} else {
|
|
|
|
|
$errorstr = $errors;
|
|
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2010-04-10 21:10:22 +00:00
|
|
|
return $errorstr
|
|
|
|
|
? Html::rawElement( 'div', array( 'class' => 'error' ), $errorstr )
|
|
|
|
|
: '';
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Format a stack of error messages into a single HTML string
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param array $errors of message keys/values
|
2012-07-15 20:32:48 +00:00
|
|
|
* @return String HTML, a "<ul>" list of errors
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2011-04-01 23:13:15 +00:00
|
|
|
public static function formatErrors( $errors ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
$errorstr = '';
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
foreach ( $errors as $error ) {
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( is_array( $error ) ) {
|
2009-06-21 18:26:29 +00:00
|
|
|
$msg = array_shift( $error );
|
2009-04-24 01:31:17 +00:00
|
|
|
} else {
|
|
|
|
|
$msg = $error;
|
|
|
|
|
$error = array();
|
|
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-09-07 01:47:45 +00:00
|
|
|
$errorstr .= Html::rawElement(
|
2009-06-21 18:26:29 +00:00
|
|
|
'li',
|
2011-04-13 16:51:22 +00:00
|
|
|
array(),
|
2012-08-19 20:44:29 +00:00
|
|
|
wfMessage( $msg, $error )->parse()
|
2009-06-21 18:26:29 +00:00
|
|
|
);
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-07 01:47:45 +00:00
|
|
|
$errorstr = Html::rawElement( 'ul', array(), $errorstr );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
return $errorstr;
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Set the text for the submit button
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $t plaintext.
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function setSubmitText( $t ) {
|
|
|
|
|
$this->mSubmitText = $t;
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2011-10-22 20:03:40 +00:00
|
|
|
/**
|
|
|
|
|
* Set the text for the submit button to a message
|
2011-10-23 01:10:23 +00:00
|
|
|
* @since 1.19
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $msg message key
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2011-10-22 20:03:40 +00:00
|
|
|
*/
|
|
|
|
|
public function setSubmitTextMsg( $msg ) {
|
2012-06-15 14:05:49 +00:00
|
|
|
$this->setSubmitText( $this->msg( $msg )->text() );
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2011-10-22 20:03:40 +00:00
|
|
|
}
|
|
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Get the text for the submit button, either customised or a default.
|
2012-02-10 15:37:33 +00:00
|
|
|
* @return string
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function getSubmitText() {
|
2009-09-28 19:04:10 +00:00
|
|
|
return $this->mSubmitText
|
2010-05-30 12:44:17 +00:00
|
|
|
? $this->mSubmitText
|
2012-08-21 20:11:18 +00:00
|
|
|
: $this->msg( 'htmlform-submit' )->text();
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2012-07-24 09:45:22 +00:00
|
|
|
/**
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $name Submit button name
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
|
|
|
|
*/
|
2009-10-18 19:29:35 +00:00
|
|
|
public function setSubmitName( $name ) {
|
|
|
|
|
$this->mSubmitName = $name;
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2009-10-18 19:29:35 +00:00
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2012-07-24 09:45:22 +00:00
|
|
|
/**
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $name Tooltip for the submit button
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
|
|
|
|
*/
|
2009-10-18 19:29:35 +00:00
|
|
|
public function setSubmitTooltip( $name ) {
|
|
|
|
|
$this->mSubmitTooltip = $name;
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2009-10-18 19:29:35 +00:00
|
|
|
}
|
|
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
2010-05-30 12:44:17 +00:00
|
|
|
* Set the id for the submit button.
|
2011-05-17 22:03:20 +00:00
|
|
|
* @param $t String.
|
|
|
|
|
* @todo FIXME: Integrity of $t is *not* validated
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function setSubmitID( $t ) {
|
|
|
|
|
$this->mSubmitID = $t;
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2013-03-09 01:30:49 +00:00
|
|
|
/**
|
|
|
|
|
* Stop a default submit button being shown for this form. This implies that an
|
|
|
|
|
* alternate submit method must be provided manually.
|
|
|
|
|
*
|
|
|
|
|
* @since 1.22
|
|
|
|
|
*
|
|
|
|
|
* @param bool $suppressSubmit Set to false to re-enable the button again
|
|
|
|
|
*
|
|
|
|
|
* @return HTMLForm $this for chaining calls
|
|
|
|
|
*/
|
|
|
|
|
function suppressDefaultSubmit( $suppressSubmit = true ) {
|
|
|
|
|
$this->mShowSubmit = !$suppressSubmit;
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-24 09:45:22 +00:00
|
|
|
/**
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $id DOM id for the form
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
|
|
|
|
*/
|
2009-10-18 19:29:35 +00:00
|
|
|
public function setId( $id ) {
|
|
|
|
|
$this->mId = $id;
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2009-10-18 19:29:35 +00:00
|
|
|
}
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
2012-07-10 12:48:06 +00:00
|
|
|
* Prompt the whole form to be wrapped in a "<fieldset>", with
|
|
|
|
|
* this text as its "<legend>" element.
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $legend HTML to go inside the "<legend>" element.
|
2009-09-28 19:04:10 +00:00
|
|
|
* Will be escaped
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2012-07-24 09:45:22 +00:00
|
|
|
public function setWrapperLegend( $legend ) {
|
|
|
|
|
$this->mWrapperLegend = $legend;
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2011-10-22 20:03:40 +00:00
|
|
|
/**
|
2012-07-10 12:48:06 +00:00
|
|
|
* Prompt the whole form to be wrapped in a "<fieldset>", with
|
|
|
|
|
* this message as its "<legend>" element.
|
2011-10-23 01:10:23 +00:00
|
|
|
* @since 1.19
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $msg message key
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2011-10-22 20:03:40 +00:00
|
|
|
*/
|
|
|
|
|
public function setWrapperLegendMsg( $msg ) {
|
2012-08-20 14:54:11 +00:00
|
|
|
$this->setWrapperLegend( $this->msg( $msg )->text() );
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2011-10-22 20:03:40 +00:00
|
|
|
}
|
|
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Set the prefix for various default messages
|
2012-07-10 12:48:06 +00:00
|
|
|
* @todo currently only used for the "<fieldset>" legend on forms
|
2013-03-13 07:42:41 +00:00
|
|
|
* with multiple sections; should be used elsewhere?
|
2009-09-28 19:04:10 +00:00
|
|
|
* @param $p String
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function setMessagePrefix( $p ) {
|
|
|
|
|
$this->mMessagePrefix = $p;
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Set the title for form submission
|
|
|
|
|
* @param $t Title of page the form is on/should be posted to
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function setTitle( $t ) {
|
|
|
|
|
$this->mTitle = $t;
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Get the title
|
|
|
|
|
* @return Title
|
|
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function getTitle() {
|
2011-04-13 16:51:22 +00:00
|
|
|
return $this->mTitle === false
|
2011-06-17 13:27:39 +00:00
|
|
|
? $this->getContext()->getTitle()
|
2011-04-13 16:51:22 +00:00
|
|
|
: $this->mTitle;
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-15 19:33:03 +00:00
|
|
|
/**
|
|
|
|
|
* Set the method used to submit the form
|
|
|
|
|
* @param $method String
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2010-12-15 19:33:03 +00:00
|
|
|
*/
|
2012-03-01 10:54:18 +00:00
|
|
|
public function setMethod( $method = 'post' ) {
|
2010-12-15 19:33:03 +00:00
|
|
|
$this->mMethod = $method;
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2010-12-15 19:33:03 +00:00
|
|
|
}
|
2011-03-05 12:48:32 +00:00
|
|
|
|
2012-03-01 10:54:18 +00:00
|
|
|
public function getMethod() {
|
2010-12-15 20:10:16 +00:00
|
|
|
return $this->mMethod;
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
2012-07-10 12:48:06 +00:00
|
|
|
* @todo Document
|
2011-10-17 15:56:25 +00:00
|
|
|
* @param $fields array[]|HTMLFormField[] array of fields (either arrays or objects)
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $sectionName ID attribute of the "<table>" tag for this section, ignored if empty
|
|
|
|
|
* @param string $fieldsetIDPrefix ID prefix for the "<fieldset>" tag of each subsection, ignored if empty
|
2011-10-17 15:56:25 +00:00
|
|
|
* @return String
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2012-05-04 22:09:33 +00:00
|
|
|
public function displaySection( $fields, $sectionName = '', $fieldsetIDPrefix = '' ) {
|
|
|
|
|
$displayFormat = $this->getDisplayFormat();
|
|
|
|
|
|
|
|
|
|
$html = '';
|
2009-04-24 01:31:17 +00:00
|
|
|
$subsectionHtml = '';
|
2012-05-04 22:09:33 +00:00
|
|
|
$hasLabel = false;
|
|
|
|
|
|
|
|
|
|
$getFieldHtmlMethod = ( $displayFormat == 'table' ) ? 'getTableRow' : 'get' . ucfirst( $displayFormat );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-05-30 12:44:17 +00:00
|
|
|
foreach ( $fields as $key => $value ) {
|
2012-05-04 22:09:33 +00:00
|
|
|
if ( $value instanceof HTMLFormField ) {
|
2009-06-21 18:26:29 +00:00
|
|
|
$v = empty( $value->mParams['nodata'] )
|
2009-09-28 19:04:10 +00:00
|
|
|
? $this->mFieldData[$key]
|
|
|
|
|
: $value->getDefault();
|
2012-05-04 22:09:33 +00:00
|
|
|
$html .= $value->$getFieldHtmlMethod( $v );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2012-05-04 22:09:33 +00:00
|
|
|
$labelValue = trim( $value->getLabel() );
|
|
|
|
|
if ( $labelValue != ' ' && $labelValue !== '' ) {
|
|
|
|
|
$hasLabel = true;
|
2011-08-24 19:48:59 +00:00
|
|
|
}
|
2009-04-24 01:31:17 +00:00
|
|
|
} elseif ( is_array( $value ) ) {
|
2013-03-05 23:21:06 +00:00
|
|
|
$section = $this->displaySection( $value, $key, "$fieldsetIDPrefix$key-" );
|
2011-03-24 22:46:07 +00:00
|
|
|
$legend = $this->getLegend( $key );
|
2011-01-25 20:56:56 +00:00
|
|
|
if ( isset( $this->mSectionHeaders[$key] ) ) {
|
|
|
|
|
$section = $this->mSectionHeaders[$key] . $section;
|
2011-05-25 15:39:47 +00:00
|
|
|
}
|
2011-01-25 20:56:56 +00:00
|
|
|
if ( isset( $this->mSectionFooters[$key] ) ) {
|
|
|
|
|
$section .= $this->mSectionFooters[$key];
|
|
|
|
|
}
|
2011-07-08 21:12:10 +00:00
|
|
|
$attributes = array();
|
2011-08-25 09:44:20 +00:00
|
|
|
if ( $fieldsetIDPrefix ) {
|
|
|
|
|
$attributes['id'] = Sanitizer::escapeId( "$fieldsetIDPrefix$key" );
|
2011-07-08 21:12:10 +00:00
|
|
|
}
|
|
|
|
|
$subsectionHtml .= Xml::fieldset( $legend, $section, $attributes ) . "\n";
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2012-05-04 22:09:33 +00:00
|
|
|
if ( $displayFormat !== 'raw' ) {
|
|
|
|
|
$classes = array();
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2012-05-04 22:09:33 +00:00
|
|
|
if ( !$hasLabel ) { // Avoid strange spacing when no labels exist
|
|
|
|
|
$classes[] = 'mw-htmlform-nolabel';
|
|
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2012-05-04 22:09:33 +00:00
|
|
|
$attribs = array(
|
|
|
|
|
'class' => implode( ' ', $classes ),
|
|
|
|
|
);
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2012-05-04 22:09:33 +00:00
|
|
|
if ( $sectionName ) {
|
|
|
|
|
$attribs['id'] = Sanitizer::escapeId( "mw-htmlform-$sectionName" );
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2012-05-04 22:09:33 +00:00
|
|
|
if ( $displayFormat === 'table' ) {
|
|
|
|
|
$html = Html::rawElement( 'table', $attribs,
|
|
|
|
|
Html::rawElement( 'tbody', array(), "\n$html\n" ) ) . "\n";
|
|
|
|
|
} elseif ( $displayFormat === 'div' ) {
|
|
|
|
|
$html = Html::rawElement( 'div', $attribs, "\n$html\n" );
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2011-10-31 14:41:02 +00:00
|
|
|
if ( $this->mSubSectionBeforeFields ) {
|
2012-05-04 22:09:33 +00:00
|
|
|
return $subsectionHtml . "\n" . $html;
|
2011-10-31 14:41:02 +00:00
|
|
|
} else {
|
2012-05-04 22:09:33 +00:00
|
|
|
return $html . "\n" . $subsectionHtml;
|
2011-10-31 14:41:02 +00:00
|
|
|
}
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Construct the form fields from the Descriptor array
|
|
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function loadData() {
|
|
|
|
|
$fieldData = array();
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-05-30 12:44:17 +00:00
|
|
|
foreach ( $this->mFlatFields as $fieldname => $field ) {
|
|
|
|
|
if ( !empty( $field->mParams['nodata'] ) ) {
|
2010-04-10 12:03:30 +00:00
|
|
|
continue;
|
|
|
|
|
} elseif ( !empty( $field->mParams['disabled'] ) ) {
|
2009-04-28 01:00:35 +00:00
|
|
|
$fieldData[$fieldname] = $field->getDefault();
|
|
|
|
|
} else {
|
2011-04-13 16:51:22 +00:00
|
|
|
$fieldData[$fieldname] = $field->loadDataFromRequest( $this->getRequest() );
|
2009-04-28 01:00:35 +00:00
|
|
|
}
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
# Filter data.
|
2010-05-30 12:44:17 +00:00
|
|
|
foreach ( $fieldData as $name => &$value ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
$field = $this->mFlatFields[$name];
|
|
|
|
|
$value = $field->filter( $value, $this->mFlatFields );
|
|
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
$this->mFieldData = $fieldData;
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Stop a reset button being shown for this form
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param bool $suppressReset set to false to re-enable the
|
2009-09-28 19:04:10 +00:00
|
|
|
* button again
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function suppressReset( $suppressReset = true ) {
|
|
|
|
|
$this->mShowReset = !$suppressReset;
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Overload this if you want to apply special filtration routines
|
2010-05-30 12:44:17 +00:00
|
|
|
* to the form as a whole, after it's submitted but before it's
|
2009-09-28 19:04:10 +00:00
|
|
|
* processed.
|
2010-05-30 12:44:17 +00:00
|
|
|
* @param $data
|
2012-02-09 19:30:01 +00:00
|
|
|
* @return
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function filterDataForSubmit( $data ) {
|
|
|
|
|
return $data;
|
|
|
|
|
}
|
2011-03-24 22:46:07 +00:00
|
|
|
|
|
|
|
|
/**
|
2012-07-10 12:48:06 +00:00
|
|
|
* Get a string to go in the "<legend>" of a section fieldset.
|
|
|
|
|
* Override this if you want something more complicated.
|
2011-03-24 22:46:07 +00:00
|
|
|
* @param $key String
|
|
|
|
|
* @return String
|
|
|
|
|
*/
|
|
|
|
|
public function getLegend( $key ) {
|
2012-08-21 20:11:18 +00:00
|
|
|
return $this->msg( "{$this->mMessagePrefix}-$key" )->text();
|
2011-03-24 22:46:07 +00:00
|
|
|
}
|
2012-01-30 11:33:16 +00:00
|
|
|
|
2012-01-29 15:23:23 +00:00
|
|
|
/**
|
|
|
|
|
* Set the value for the action attribute of the form.
|
2012-01-30 11:33:16 +00:00
|
|
|
* When set to false (which is the default state), the set title is used.
|
|
|
|
|
*
|
2012-01-29 15:23:23 +00:00
|
|
|
* @since 1.19
|
2012-01-30 11:33:16 +00:00
|
|
|
*
|
2012-02-09 18:01:10 +00:00
|
|
|
* @param string|bool $action
|
2012-07-24 09:45:22 +00:00
|
|
|
* @return HTMLForm $this for chaining calls (since 1.20)
|
2012-01-29 15:23:23 +00:00
|
|
|
*/
|
|
|
|
|
public function setAction( $action ) {
|
|
|
|
|
$this->mAction = $action;
|
2012-07-24 09:45:22 +00:00
|
|
|
return $this;
|
2012-01-29 15:23:23 +00:00
|
|
|
}
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
|
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
2010-05-30 12:44:17 +00:00
|
|
|
* The parent class to generate form fields. Any field type should
|
2009-09-28 19:04:10 +00:00
|
|
|
* be a subclass of this.
|
|
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
abstract class HTMLFormField {
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
protected $mValidationCallback;
|
|
|
|
|
protected $mFilterCallback;
|
|
|
|
|
protected $mName;
|
|
|
|
|
public $mParams;
|
|
|
|
|
protected $mLabel; # String label. Set on construction
|
|
|
|
|
protected $mID;
|
2010-04-10 12:03:30 +00:00
|
|
|
protected $mClass = '';
|
2009-09-28 19:04:10 +00:00
|
|
|
protected $mDefault;
|
2011-04-23 21:27:24 +00:00
|
|
|
|
2013-04-16 18:05:50 +00:00
|
|
|
/**
|
|
|
|
|
* @var bool If true will generate an empty div element with no label
|
|
|
|
|
* @since 1.22
|
|
|
|
|
*/
|
|
|
|
|
protected $mShowEmptyLabels = true;
|
|
|
|
|
|
2011-04-23 21:27:24 +00:00
|
|
|
/**
|
|
|
|
|
* @var HTMLForm
|
|
|
|
|
*/
|
2009-09-28 19:04:10 +00:00
|
|
|
public $mParent;
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* This function must be implemented to return the HTML to generate
|
|
|
|
|
* the input object itself. It should not implement the surrounding
|
|
|
|
|
* table cells/rows, or labels/help messages.
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $value the value to set the input to; eg a default
|
2010-05-30 12:44:17 +00:00
|
|
|
* text for a text input.
|
2009-09-28 19:04:10 +00:00
|
|
|
* @return String valid HTML.
|
|
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
abstract function getInputHTML( $value );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2012-08-23 07:11:21 +00:00
|
|
|
/**
|
|
|
|
|
* Get a translated interface message
|
|
|
|
|
*
|
2013-03-13 07:42:41 +00:00
|
|
|
* This is a wrapper around $this->mParent->msg() if $this->mParent is set
|
2012-08-23 07:11:21 +00:00
|
|
|
* and wfMessage() otherwise.
|
|
|
|
|
*
|
|
|
|
|
* Parameters are the same as wfMessage().
|
|
|
|
|
*
|
|
|
|
|
* @return Message object
|
|
|
|
|
*/
|
|
|
|
|
function msg() {
|
|
|
|
|
$args = func_get_args();
|
|
|
|
|
|
|
|
|
|
if ( $this->mParent ) {
|
|
|
|
|
$callback = array( $this->mParent, 'msg' );
|
|
|
|
|
} else {
|
|
|
|
|
$callback = 'wfMessage';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return call_user_func_array( $callback, $args );
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
2010-05-30 12:44:17 +00:00
|
|
|
* Override this function to add specific validation checks on the
|
2009-09-28 19:04:10 +00:00
|
|
|
* field input. Don't forget to call parent::validate() to ensure
|
|
|
|
|
* that the user-defined callback mValidationCallback is still run
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $value the value the field was submitted with
|
|
|
|
|
* @param array $alldata the data collected from the form
|
2009-09-28 19:04:10 +00:00
|
|
|
* @return Mixed Bool true on success, or String error to display.
|
|
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function validate( $value, $alldata ) {
|
2012-08-11 22:23:46 +00:00
|
|
|
if ( isset( $this->mParams['required'] ) && $this->mParams['required'] !== false && $value === '' ) {
|
2012-08-23 07:11:21 +00:00
|
|
|
return $this->msg( 'htmlform-required' )->parse();
|
2010-12-12 15:32:29 +00:00
|
|
|
}
|
|
|
|
|
|
2011-10-08 19:13:35 +00:00
|
|
|
if ( isset( $this->mValidationCallback ) ) {
|
2011-11-13 07:25:56 +00:00
|
|
|
return call_user_func( $this->mValidationCallback, $value, $alldata, $this->mParent );
|
2011-10-08 19:13:35 +00:00
|
|
|
}
|
|
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
function filter( $value, $alldata ) {
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( isset( $this->mFilterCallback ) ) {
|
2011-11-13 07:25:56 +00:00
|
|
|
$value = call_user_func( $this->mFilterCallback, $value, $alldata, $this->mParent );
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
return $value;
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-07 01:48:06 +00:00
|
|
|
/**
|
|
|
|
|
* Should this field have a label, or is there no input element with the
|
|
|
|
|
* appropriate id for the label to point to?
|
|
|
|
|
*
|
|
|
|
|
* @return bool True to output a label, false to suppress
|
|
|
|
|
*/
|
|
|
|
|
protected function needsLabel() {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Get the value that this input has been set to from a posted form,
|
|
|
|
|
* or the input's default value if it has not been set.
|
|
|
|
|
* @param $request WebRequest
|
|
|
|
|
* @return String the value
|
|
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function loadDataFromRequest( $request ) {
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( $request->getCheck( $this->mName ) ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
return $request->getText( $this->mName );
|
|
|
|
|
} else {
|
|
|
|
|
return $this->getDefault();
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Initialise the object
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param array $params Associative Array. See HTMLForm doc for syntax.
|
2013-04-16 18:05:50 +00:00
|
|
|
*
|
|
|
|
|
* @since 1.22 The 'label' attribute no longer accepts raw HTML, use 'label-raw' instead
|
2012-10-07 23:35:26 +00:00
|
|
|
* @throws MWException
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function __construct( $params ) {
|
|
|
|
|
$this->mParams = $params;
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
# Generate the label from a message, if possible
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( isset( $params['label-message'] ) ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
$msgInfo = $params['label-message'];
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
if ( is_array( $msgInfo ) ) {
|
|
|
|
|
$msg = array_shift( $msgInfo );
|
|
|
|
|
} else {
|
|
|
|
|
$msg = $msgInfo;
|
|
|
|
|
$msgInfo = array();
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2012-08-19 20:44:29 +00:00
|
|
|
$this->mLabel = wfMessage( $msg, $msgInfo )->parse();
|
2009-06-21 18:26:29 +00:00
|
|
|
} elseif ( isset( $params['label'] ) ) {
|
2013-04-16 18:05:50 +00:00
|
|
|
if ( $params['label'] === ' ' ) {
|
|
|
|
|
// Apparently some things set   directly and in an odd format
|
|
|
|
|
$this->mLabel = ' ';
|
|
|
|
|
} else {
|
|
|
|
|
$this->mLabel = htmlspecialchars( $params['label'] );
|
|
|
|
|
}
|
|
|
|
|
} elseif ( isset( $params['label-raw'] ) ) {
|
|
|
|
|
$this->mLabel = $params['label-raw'];
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-12-15 21:14:36 +00:00
|
|
|
$this->mName = "wp{$params['fieldname']}";
|
2009-04-24 01:31:17 +00:00
|
|
|
if ( isset( $params['name'] ) ) {
|
2010-12-15 21:14:36 +00:00
|
|
|
$this->mName = $params['name'];
|
|
|
|
|
}
|
2011-03-05 12:48:32 +00:00
|
|
|
|
2010-12-15 21:14:36 +00:00
|
|
|
$validName = Sanitizer::escapeId( $this->mName );
|
|
|
|
|
if ( $this->mName != $validName && !isset( $params['nodata'] ) ) {
|
|
|
|
|
throw new MWException( "Invalid name '{$this->mName}' passed to " . __METHOD__ );
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2011-03-05 12:48:32 +00:00
|
|
|
|
2010-12-15 21:14:36 +00:00
|
|
|
$this->mID = "mw-input-{$this->mName}";
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
if ( isset( $params['default'] ) ) {
|
|
|
|
|
$this->mDefault = $params['default'];
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
if ( isset( $params['id'] ) ) {
|
2009-07-19 16:49:58 +00:00
|
|
|
$id = $params['id'];
|
|
|
|
|
$validId = Sanitizer::escapeId( $id );
|
2010-05-30 12:44:17 +00:00
|
|
|
|
|
|
|
|
if ( $id != $validId ) {
|
|
|
|
|
throw new MWException( "Invalid id '$id' passed to " . __METHOD__ );
|
2009-07-19 16:49:58 +00:00
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-07-19 16:49:58 +00:00
|
|
|
$this->mID = $id;
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-04-10 12:03:30 +00:00
|
|
|
if ( isset( $params['cssclass'] ) ) {
|
|
|
|
|
$this->mClass = $params['cssclass'];
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
if ( isset( $params['validation-callback'] ) ) {
|
|
|
|
|
$this->mValidationCallback = $params['validation-callback'];
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
if ( isset( $params['filter-callback'] ) ) {
|
|
|
|
|
$this->mFilterCallback = $params['filter-callback'];
|
|
|
|
|
}
|
2011-12-23 20:35:57 +00:00
|
|
|
|
2012-05-04 22:09:33 +00:00
|
|
|
if ( isset( $params['flatlist'] ) ) {
|
2011-12-23 20:35:57 +00:00
|
|
|
$this->mClass .= ' mw-htmlform-flatlist';
|
|
|
|
|
}
|
2013-04-16 18:05:50 +00:00
|
|
|
|
|
|
|
|
if ( isset( $params['hidelabel'] ) ) {
|
|
|
|
|
$this->mShowEmptyLabels = false;
|
|
|
|
|
}
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Get the complete table row for the input, including help text,
|
|
|
|
|
* labels, and whatever.
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $value the value to set the input to.
|
2009-09-28 19:04:10 +00:00
|
|
|
* @return String complete HTML table row.
|
|
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function getTableRow( $value ) {
|
2012-05-04 22:09:33 +00:00
|
|
|
list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
|
|
|
|
|
$inputHtml = $this->getInputHTML( $value );
|
|
|
|
|
$fieldType = get_class( $this );
|
|
|
|
|
$helptext = $this->getHelpTextHtmlTable( $this->getHelpText() );
|
2010-07-02 21:20:54 +00:00
|
|
|
$cellAttributes = array();
|
2011-03-05 12:48:32 +00:00
|
|
|
|
2012-05-04 22:09:33 +00:00
|
|
|
if ( !empty( $this->mParams['vertical-label'] ) ) {
|
2010-07-02 21:20:54 +00:00
|
|
|
$cellAttributes['colspan'] = 2;
|
|
|
|
|
$verticalLabel = true;
|
2009-04-24 01:31:17 +00:00
|
|
|
} else {
|
2012-05-04 22:09:33 +00:00
|
|
|
$verticalLabel = false;
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-07-02 21:20:54 +00:00
|
|
|
$label = $this->getLabelHtml( $cellAttributes );
|
2012-05-04 22:09:33 +00:00
|
|
|
|
2010-07-02 21:20:54 +00:00
|
|
|
$field = Html::rawElement(
|
2010-05-30 12:44:17 +00:00
|
|
|
'td',
|
2010-07-02 21:20:54 +00:00
|
|
|
array( 'class' => 'mw-input' ) + $cellAttributes,
|
2012-05-04 22:09:33 +00:00
|
|
|
$inputHtml . "\n$errors"
|
2010-04-10 12:03:30 +00:00
|
|
|
);
|
2011-03-05 12:48:32 +00:00
|
|
|
|
2011-03-13 09:51:47 +00:00
|
|
|
if ( $verticalLabel ) {
|
2010-07-02 21:20:54 +00:00
|
|
|
$html = Html::rawElement( 'tr',
|
|
|
|
|
array( 'class' => 'mw-htmlform-vertical-label' ), $label );
|
|
|
|
|
$html .= Html::rawElement( 'tr',
|
2011-03-13 09:51:47 +00:00
|
|
|
array( 'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass" ),
|
2010-07-02 21:20:54 +00:00
|
|
|
$field );
|
|
|
|
|
} else {
|
|
|
|
|
$html = Html::rawElement( 'tr',
|
2011-03-13 09:51:47 +00:00
|
|
|
array( 'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass" ),
|
2010-07-02 21:20:54 +00:00
|
|
|
$label . $field );
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2012-05-04 22:09:33 +00:00
|
|
|
return $html . $helptext;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the complete div for the input, including help text,
|
|
|
|
|
* labels, and whatever.
|
|
|
|
|
* @since 1.20
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $value the value to set the input to.
|
2012-05-04 22:09:33 +00:00
|
|
|
* @return String complete HTML table row.
|
|
|
|
|
*/
|
|
|
|
|
public function getDiv( $value ) {
|
|
|
|
|
list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
|
|
|
|
|
$inputHtml = $this->getInputHTML( $value );
|
|
|
|
|
$fieldType = get_class( $this );
|
|
|
|
|
$helptext = $this->getHelpTextHtmlDiv( $this->getHelpText() );
|
|
|
|
|
$cellAttributes = array();
|
|
|
|
|
$label = $this->getLabelHtml( $cellAttributes );
|
|
|
|
|
|
2013-04-16 18:05:50 +00:00
|
|
|
$outerDivClass = array(
|
|
|
|
|
'mw-input',
|
|
|
|
|
'mw-htmlform-nolabel' => ( $label === '' )
|
|
|
|
|
);
|
|
|
|
|
|
2012-05-04 22:09:33 +00:00
|
|
|
$field = Html::rawElement(
|
|
|
|
|
'div',
|
2013-04-16 18:05:50 +00:00
|
|
|
array( 'class' => $outerDivClass ) + $cellAttributes,
|
2012-05-04 22:09:33 +00:00
|
|
|
$inputHtml . "\n$errors"
|
|
|
|
|
);
|
|
|
|
|
$html = Html::rawElement( 'div',
|
|
|
|
|
array( 'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass" ),
|
|
|
|
|
$label . $field );
|
|
|
|
|
$html .= $helptext;
|
|
|
|
|
return $html;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the complete raw fields for the input, including help text,
|
|
|
|
|
* labels, and whatever.
|
|
|
|
|
* @since 1.20
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $value the value to set the input to.
|
2012-05-04 22:09:33 +00:00
|
|
|
* @return String complete HTML table row.
|
|
|
|
|
*/
|
|
|
|
|
public function getRaw( $value ) {
|
2012-12-09 03:27:02 +00:00
|
|
|
list( $errors, ) = $this->getErrorsAndErrorClass( $value );
|
2012-05-04 22:09:33 +00:00
|
|
|
$inputHtml = $this->getInputHTML( $value );
|
|
|
|
|
$helptext = $this->getHelpTextHtmlRaw( $this->getHelpText() );
|
|
|
|
|
$cellAttributes = array();
|
|
|
|
|
$label = $this->getLabelHtml( $cellAttributes );
|
|
|
|
|
|
|
|
|
|
$html = "\n$errors";
|
|
|
|
|
$html .= $label;
|
|
|
|
|
$html .= $inputHtml;
|
|
|
|
|
$html .= $helptext;
|
|
|
|
|
return $html;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Generate help text HTML in table format
|
|
|
|
|
* @since 1.20
|
|
|
|
|
* @param $helptext String|null
|
|
|
|
|
* @return String
|
|
|
|
|
*/
|
|
|
|
|
public function getHelpTextHtmlTable( $helptext ) {
|
|
|
|
|
if ( is_null( $helptext ) ) {
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$row = Html::rawElement(
|
|
|
|
|
'td',
|
|
|
|
|
array( 'colspan' => 2, 'class' => 'htmlform-tip' ),
|
|
|
|
|
$helptext
|
|
|
|
|
);
|
|
|
|
|
$row = Html::rawElement( 'tr', array(), $row );
|
|
|
|
|
return $row;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Generate help text HTML in div format
|
|
|
|
|
* @since 1.20
|
|
|
|
|
* @param $helptext String|null
|
|
|
|
|
* @return String
|
|
|
|
|
*/
|
|
|
|
|
public function getHelpTextHtmlDiv( $helptext ) {
|
|
|
|
|
if ( is_null( $helptext ) ) {
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$div = Html::rawElement( 'div', array( 'class' => 'htmlform-tip' ), $helptext );
|
|
|
|
|
return $div;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Generate help text HTML formatted for raw output
|
|
|
|
|
* @since 1.20
|
|
|
|
|
* @param $helptext String|null
|
|
|
|
|
* @return String
|
|
|
|
|
*/
|
|
|
|
|
public function getHelpTextHtmlRaw( $helptext ) {
|
|
|
|
|
return $this->getHelpTextHtmlDiv( $helptext );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Determine the help text to display
|
|
|
|
|
* @since 1.20
|
|
|
|
|
* @return String
|
|
|
|
|
*/
|
|
|
|
|
public function getHelpText() {
|
2009-07-24 01:22:06 +00:00
|
|
|
$helptext = null;
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-06-21 18:26:29 +00:00
|
|
|
if ( isset( $this->mParams['help-message'] ) ) {
|
2012-03-07 19:07:40 +00:00
|
|
|
$this->mParams['help-messages'] = array( $this->mParams['help-message'] );
|
2012-03-06 15:36:08 +00:00
|
|
|
}
|
2012-03-06 00:32:48 +00:00
|
|
|
|
2012-03-06 15:36:08 +00:00
|
|
|
if ( isset( $this->mParams['help-messages'] ) ) {
|
2012-05-04 22:09:33 +00:00
|
|
|
foreach ( $this->mParams['help-messages'] as $name ) {
|
2012-03-06 00:32:48 +00:00
|
|
|
$helpMessage = (array)$name;
|
2012-08-23 07:11:21 +00:00
|
|
|
$msg = $this->msg( array_shift( $helpMessage ), $helpMessage );
|
2012-03-06 00:32:48 +00:00
|
|
|
|
2012-05-04 22:09:33 +00:00
|
|
|
if ( $msg->exists() ) {
|
|
|
|
|
if ( is_null( $helptext ) ) {
|
2012-04-21 09:55:40 +00:00
|
|
|
$helptext = '';
|
|
|
|
|
} else {
|
2012-08-23 07:11:21 +00:00
|
|
|
$helptext .= $this->msg( 'word-separator' )->escaped(); // some space
|
2012-04-21 09:55:40 +00:00
|
|
|
}
|
2012-03-06 15:36:08 +00:00
|
|
|
$helptext .= $msg->parse(); // Append message
|
2011-01-14 16:53:36 +00:00
|
|
|
}
|
2011-05-24 17:28:21 +00:00
|
|
|
}
|
2012-03-06 15:36:08 +00:00
|
|
|
}
|
|
|
|
|
elseif ( isset( $this->mParams['help'] ) ) {
|
2009-07-24 01:22:06 +00:00
|
|
|
$helptext = $this->mParams['help'];
|
|
|
|
|
}
|
2012-05-04 22:09:33 +00:00
|
|
|
return $helptext;
|
|
|
|
|
}
|
2009-07-24 01:22:06 +00:00
|
|
|
|
2012-05-04 22:09:33 +00:00
|
|
|
/**
|
|
|
|
|
* Determine form errors to display and their classes
|
|
|
|
|
* @since 1.20
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $value the value of the input
|
2012-05-04 22:09:33 +00:00
|
|
|
* @return Array
|
|
|
|
|
*/
|
|
|
|
|
public function getErrorsAndErrorClass( $value ) {
|
|
|
|
|
$errors = $this->validate( $value, $this->mParent->mFieldData );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2012-05-04 22:09:33 +00:00
|
|
|
if ( $errors === true || ( !$this->mParent->getRequest()->wasPosted() && ( $this->mParent->getMethod() == 'post' ) ) ) {
|
|
|
|
|
$errors = '';
|
|
|
|
|
$errorClass = '';
|
|
|
|
|
} else {
|
|
|
|
|
$errors = self::formatErrors( $errors );
|
|
|
|
|
$errorClass = 'mw-htmlform-invalid-input';
|
|
|
|
|
}
|
|
|
|
|
return array( $errors, $errorClass );
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
function getLabel() {
|
2013-04-16 18:05:50 +00:00
|
|
|
return is_null( $this->mLabel ) ? '' : $this->mLabel;
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2012-05-04 22:09:33 +00:00
|
|
|
|
2010-07-02 21:20:54 +00:00
|
|
|
function getLabelHtml( $cellAttributes = array() ) {
|
2009-10-09 14:22:37 +00:00
|
|
|
# Don't output a for= attribute for labels with no associated input.
|
|
|
|
|
# Kind of hacky here, possibly we don't want these to be <label>s at all.
|
|
|
|
|
$for = array();
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-10-09 14:22:37 +00:00
|
|
|
if ( $this->needsLabel() ) {
|
|
|
|
|
$for['for'] = $this->mID;
|
|
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2013-04-16 18:05:50 +00:00
|
|
|
$labelValue = trim( $this->getLabel() );
|
|
|
|
|
$hasLabel = false;
|
|
|
|
|
if ( $labelValue !== ' ' && $labelValue !== '' ) {
|
|
|
|
|
$hasLabel = true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-04 22:09:33 +00:00
|
|
|
$displayFormat = $this->mParent->getDisplayFormat();
|
2013-04-16 18:05:50 +00:00
|
|
|
$html = '';
|
2012-05-04 22:09:33 +00:00
|
|
|
|
2013-04-16 18:05:50 +00:00
|
|
|
if ( $displayFormat === 'table' ) {
|
|
|
|
|
$html = Html::rawElement( 'td', array( 'class' => 'mw-label' ) + $cellAttributes,
|
|
|
|
|
Html::rawElement( 'label', $for, $labelValue )
|
2012-05-04 22:09:33 +00:00
|
|
|
);
|
2013-04-16 18:05:50 +00:00
|
|
|
} elseif ( $hasLabel || $this->mShowEmptyLabels ) {
|
|
|
|
|
if ( $displayFormat === 'div' ) {
|
|
|
|
|
$html = Html::rawElement(
|
|
|
|
|
'div',
|
|
|
|
|
array( 'class' => 'mw-label' ) + $cellAttributes,
|
|
|
|
|
Html::rawElement( 'label', $for, $labelValue )
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
$html = Html::rawElement( 'label', $for, $labelValue );
|
|
|
|
|
}
|
2012-05-04 22:09:33 +00:00
|
|
|
}
|
2013-04-16 18:05:50 +00:00
|
|
|
|
|
|
|
|
return $html;
|
2009-10-09 14:22:37 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
function getDefault() {
|
|
|
|
|
if ( isset( $this->mDefault ) ) {
|
|
|
|
|
return $this->mDefault;
|
|
|
|
|
} else {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-10-18 19:29:35 +00:00
|
|
|
/**
|
|
|
|
|
* Returns the attributes required for the tooltip and accesskey.
|
2010-05-30 12:44:17 +00:00
|
|
|
*
|
2009-10-18 19:29:35 +00:00
|
|
|
* @return array Attributes
|
|
|
|
|
*/
|
|
|
|
|
public function getTooltipAndAccessKey() {
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( empty( $this->mParams['tooltip'] ) ) {
|
2009-10-18 19:29:35 +00:00
|
|
|
return array();
|
2010-05-30 12:44:17 +00:00
|
|
|
}
|
2011-07-04 08:28:27 +00:00
|
|
|
return Linker::tooltipAndAccesskeyAttribs( $this->mParams['tooltip'] );
|
2009-10-18 19:29:35 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* flatten an array of options to a single array, for instance,
|
2012-07-10 12:48:06 +00:00
|
|
|
* a set of "<options>" inside "<optgroups>".
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param array $options Associative Array with values either Strings
|
2009-09-28 19:04:10 +00:00
|
|
|
* or Arrays
|
|
|
|
|
* @return Array flattened input
|
|
|
|
|
*/
|
|
|
|
|
public static function flattenOptions( $options ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
$flatOpts = array();
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-10-14 20:53:04 +00:00
|
|
|
foreach ( $options as $value ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
if ( is_array( $value ) ) {
|
|
|
|
|
$flatOpts = array_merge( $flatOpts, self::flattenOptions( $value ) );
|
|
|
|
|
} else {
|
|
|
|
|
$flatOpts[] = $value;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
return $flatOpts;
|
|
|
|
|
}
|
2011-03-13 09:51:47 +00:00
|
|
|
|
|
|
|
|
/**
|
2011-03-13 10:02:56 +00:00
|
|
|
* Formats one or more errors as accepted by field validation-callback.
|
2011-03-13 09:51:47 +00:00
|
|
|
* @param $errors String|Message|Array of strings or Message instances
|
|
|
|
|
* @return String html
|
2011-03-13 10:02:56 +00:00
|
|
|
* @since 1.18
|
2011-03-13 09:51:47 +00:00
|
|
|
*/
|
|
|
|
|
protected static function formatErrors( $errors ) {
|
|
|
|
|
if ( is_array( $errors ) && count( $errors ) === 1 ) {
|
|
|
|
|
$errors = array_shift( $errors );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( is_array( $errors ) ) {
|
|
|
|
|
$lines = array();
|
|
|
|
|
foreach ( $errors as $error ) {
|
|
|
|
|
if ( $error instanceof Message ) {
|
|
|
|
|
$lines[] = Html::rawElement( 'li', array(), $error->parse() );
|
|
|
|
|
} else {
|
|
|
|
|
$lines[] = Html::rawElement( 'li', array(), $error );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return Html::rawElement( 'ul', array( 'class' => 'error' ), implode( "\n", $lines ) );
|
|
|
|
|
} else {
|
|
|
|
|
if ( $errors instanceof Message ) {
|
|
|
|
|
$errors = $errors->parse();
|
|
|
|
|
}
|
|
|
|
|
return Html::rawElement( 'span', array( 'class' => 'error' ), $errors );
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class HTMLTextField extends HTMLFormField {
|
|
|
|
|
function getSize() {
|
2010-05-30 12:44:17 +00:00
|
|
|
return isset( $this->mParams['size'] )
|
|
|
|
|
? $this->mParams['size']
|
2009-09-28 19:04:10 +00:00
|
|
|
: 45;
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getInputHTML( $value ) {
|
2009-09-06 15:07:29 +00:00
|
|
|
$attribs = array(
|
|
|
|
|
'id' => $this->mID,
|
|
|
|
|
'name' => $this->mName,
|
|
|
|
|
'size' => $this->getSize(),
|
|
|
|
|
'value' => $value,
|
2009-10-18 19:29:35 +00:00
|
|
|
) + $this->getTooltipAndAccessKey();
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2011-12-21 01:10:51 +00:00
|
|
|
if ( $this->mClass !== '' ) {
|
|
|
|
|
$attribs['class'] = $this->mClass;
|
|
|
|
|
}
|
2012-05-04 22:09:33 +00:00
|
|
|
|
Start using some HTML 5 form features
autofocus attribute added in some places; this looks like it's respected
by both recent Opera and recent WebKit. Its function is
self-explanatory. :) I used this in a few obvious places like
Special:UserLogin and Special:ResetPass to focus the first field in the
form. Could be used in other places too: Special:Search, etc.
required attribute added in some places. This is only supported in
recent Opera at the moment. Also self-explanatory: it won't allow form
submission if the field is empty.
For stuff using HTMLForm (i.e., Special:Preferences), validation will be
done for integers and floats. Browsers that support this (recent Opera)
will not allow non-integers to be submitted for integer fields, will not
allow non-floating-point values to be submitted for float fields, and
will enforce any min/max values specified. Opera also gives little up
and down arrows to allow the user to increment/decrement the value in
addition to letting them edit the field as text.
For HTMLForm and account creation, the email input type is used for
e-mails. This enforces a sane set of values for e-mails (alphanumerics
plus some ASCII punctuation, with an @ in it). Again, this is supported
only by recent Opera (yay Opera!). Note that this is actually more
restrictive than what we currently check for on the server side; it
might be sane to tighten up our server-side checks to forbid e-mail
addresses that HTML 5 forbids.
In all cases, the extra features aren't added if $wgHtml5 is false, and
will be ignored by non-supporting browsers.
The major room for further improvement here is use of the pattern
attribute. We can have the client refuse to submit the form unless it
matches a regex! The HTML 5 spec says that if a title attribute is
provided, it should be a message that explains what the valid values
are and browsers should provide it to the user if the regex doesn't
match, so it's not a usability problem. I didn't bother adding that
anywhere at this point because it would require adding new messages, but
it should be easy to do. Note of course that HTMLForm should be updated
to verify that pattern matches on the server side as well -- this way we
have a clean, unified way of ensuring that our client and server checks
are the same.
2009-08-07 03:32:20 +00:00
|
|
|
if ( !empty( $this->mParams['disabled'] ) ) {
|
2009-04-28 01:00:35 +00:00
|
|
|
$attribs['disabled'] = 'disabled';
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-11-19 01:24:58 +00:00
|
|
|
# TODO: Enforce pattern, step, required, readonly on the server side as
|
|
|
|
|
# well
|
2012-08-18 01:32:51 +00:00
|
|
|
$allowedParams = array( 'min', 'max', 'pattern', 'title', 'step',
|
|
|
|
|
'placeholder', 'list', 'maxlength' );
|
|
|
|
|
foreach ( $allowedParams as $param ) {
|
2009-11-19 01:24:58 +00:00
|
|
|
if ( isset( $this->mParams[$param] ) ) {
|
|
|
|
|
$attribs[$param] = $this->mParams[$param];
|
Start using some HTML 5 form features
autofocus attribute added in some places; this looks like it's respected
by both recent Opera and recent WebKit. Its function is
self-explanatory. :) I used this in a few obvious places like
Special:UserLogin and Special:ResetPass to focus the first field in the
form. Could be used in other places too: Special:Search, etc.
required attribute added in some places. This is only supported in
recent Opera at the moment. Also self-explanatory: it won't allow form
submission if the field is empty.
For stuff using HTMLForm (i.e., Special:Preferences), validation will be
done for integers and floats. Browsers that support this (recent Opera)
will not allow non-integers to be submitted for integer fields, will not
allow non-floating-point values to be submitted for float fields, and
will enforce any min/max values specified. Opera also gives little up
and down arrows to allow the user to increment/decrement the value in
addition to letting them edit the field as text.
For HTMLForm and account creation, the email input type is used for
e-mails. This enforces a sane set of values for e-mails (alphanumerics
plus some ASCII punctuation, with an @ in it). Again, this is supported
only by recent Opera (yay Opera!). Note that this is actually more
restrictive than what we currently check for on the server side; it
might be sane to tighten up our server-side checks to forbid e-mail
addresses that HTML 5 forbids.
In all cases, the extra features aren't added if $wgHtml5 is false, and
will be ignored by non-supporting browsers.
The major room for further improvement here is use of the pattern
attribute. We can have the client refuse to submit the form unless it
matches a regex! The HTML 5 spec says that if a title attribute is
provided, it should be a message that explains what the valid values
are and browsers should provide it to the user if the regex doesn't
match, so it's not a usability problem. I didn't bother adding that
anywhere at this point because it would require adding new messages, but
it should be easy to do. Note of course that HTMLForm should be updated
to verify that pattern matches on the server side as well -- this way we
have a clean, unified way of ensuring that our client and server checks
are the same.
2009-08-07 03:32:20 +00:00
|
|
|
}
|
2009-11-19 01:24:58 +00:00
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
|
|
|
|
foreach ( array( 'required', 'autofocus', 'multiple', 'readonly' ) as $param ) {
|
2009-11-19 01:24:58 +00:00
|
|
|
if ( isset( $this->mParams[$param] ) ) {
|
|
|
|
|
$attribs[$param] = '';
|
Start using some HTML 5 form features
autofocus attribute added in some places; this looks like it's respected
by both recent Opera and recent WebKit. Its function is
self-explanatory. :) I used this in a few obvious places like
Special:UserLogin and Special:ResetPass to focus the first field in the
form. Could be used in other places too: Special:Search, etc.
required attribute added in some places. This is only supported in
recent Opera at the moment. Also self-explanatory: it won't allow form
submission if the field is empty.
For stuff using HTMLForm (i.e., Special:Preferences), validation will be
done for integers and floats. Browsers that support this (recent Opera)
will not allow non-integers to be submitted for integer fields, will not
allow non-floating-point values to be submitted for float fields, and
will enforce any min/max values specified. Opera also gives little up
and down arrows to allow the user to increment/decrement the value in
addition to letting them edit the field as text.
For HTMLForm and account creation, the email input type is used for
e-mails. This enforces a sane set of values for e-mails (alphanumerics
plus some ASCII punctuation, with an @ in it). Again, this is supported
only by recent Opera (yay Opera!). Note that this is actually more
restrictive than what we currently check for on the server side; it
might be sane to tighten up our server-side checks to forbid e-mail
addresses that HTML 5 forbids.
In all cases, the extra features aren't added if $wgHtml5 is false, and
will be ignored by non-supporting browsers.
The major room for further improvement here is use of the pattern
attribute. We can have the client refuse to submit the form unless it
matches a regex! The HTML 5 spec says that if a title attribute is
provided, it should be a message that explains what the valid values
are and browsers should provide it to the user if the regex doesn't
match, so it's not a usability problem. I didn't bother adding that
anywhere at this point because it would require adding new messages, but
it should be easy to do. Note of course that HTMLForm should be updated
to verify that pattern matches on the server side as well -- this way we
have a clean, unified way of ensuring that our client and server checks
are the same.
2009-08-07 03:32:20 +00:00
|
|
|
}
|
2009-09-30 09:46:48 +00:00
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-09-30 09:46:48 +00:00
|
|
|
# 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.
|
|
|
|
|
if ( isset( $this->mParams['type'] ) ) {
|
2009-11-19 01:24:58 +00:00
|
|
|
switch ( $this->mParams['type'] ) {
|
|
|
|
|
case 'email':
|
|
|
|
|
$attribs['type'] = 'email';
|
|
|
|
|
break;
|
|
|
|
|
case 'int':
|
|
|
|
|
$attribs['type'] = 'number';
|
|
|
|
|
break;
|
|
|
|
|
case 'float':
|
|
|
|
|
$attribs['type'] = 'number';
|
|
|
|
|
$attribs['step'] = 'any';
|
|
|
|
|
break;
|
2009-10-09 14:22:37 +00:00
|
|
|
# Pass through
|
2009-09-30 09:46:48 +00:00
|
|
|
case 'password':
|
2009-10-09 14:22:37 +00:00
|
|
|
case 'file':
|
|
|
|
|
$attribs['type'] = $this->mParams['type'];
|
2009-09-30 09:46:48 +00:00
|
|
|
break;
|
|
|
|
|
}
|
Start using some HTML 5 form features
autofocus attribute added in some places; this looks like it's respected
by both recent Opera and recent WebKit. Its function is
self-explanatory. :) I used this in a few obvious places like
Special:UserLogin and Special:ResetPass to focus the first field in the
form. Could be used in other places too: Special:Search, etc.
required attribute added in some places. This is only supported in
recent Opera at the moment. Also self-explanatory: it won't allow form
submission if the field is empty.
For stuff using HTMLForm (i.e., Special:Preferences), validation will be
done for integers and floats. Browsers that support this (recent Opera)
will not allow non-integers to be submitted for integer fields, will not
allow non-floating-point values to be submitted for float fields, and
will enforce any min/max values specified. Opera also gives little up
and down arrows to allow the user to increment/decrement the value in
addition to letting them edit the field as text.
For HTMLForm and account creation, the email input type is used for
e-mails. This enforces a sane set of values for e-mails (alphanumerics
plus some ASCII punctuation, with an @ in it). Again, this is supported
only by recent Opera (yay Opera!). Note that this is actually more
restrictive than what we currently check for on the server side; it
might be sane to tighten up our server-side checks to forbid e-mail
addresses that HTML 5 forbids.
In all cases, the extra features aren't added if $wgHtml5 is false, and
will be ignored by non-supporting browsers.
The major room for further improvement here is use of the pattern
attribute. We can have the client refuse to submit the form unless it
matches a regex! The HTML 5 spec says that if a title attribute is
provided, it should be a message that explains what the valid values
are and browsers should provide it to the user if the regex doesn't
match, so it's not a usability problem. I didn't bother adding that
anywhere at this point because it would require adding new messages, but
it should be easy to do. Note of course that HTMLForm should be updated
to verify that pattern matches on the server side as well -- this way we
have a clean, unified way of ensuring that our client and server checks
are the same.
2009-08-07 03:32:20 +00:00
|
|
|
}
|
|
|
|
|
|
2009-09-06 15:07:29 +00:00
|
|
|
return Html::element( 'input', $attribs );
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-10-09 14:22:37 +00:00
|
|
|
class HTMLTextAreaField extends HTMLFormField {
|
2013-04-13 23:06:43 +00:00
|
|
|
const DEFAULT_COLS = 80;
|
|
|
|
|
const DEFAULT_ROWS = 25;
|
|
|
|
|
|
2009-10-09 14:22:37 +00:00
|
|
|
function getCols() {
|
2010-05-30 12:44:17 +00:00
|
|
|
return isset( $this->mParams['cols'] )
|
|
|
|
|
? $this->mParams['cols']
|
2013-04-13 23:06:43 +00:00
|
|
|
: static::DEFAULT_COLS;
|
2009-10-09 14:22:37 +00:00
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-10-09 14:22:37 +00:00
|
|
|
function getRows() {
|
2010-05-30 12:44:17 +00:00
|
|
|
return isset( $this->mParams['rows'] )
|
|
|
|
|
? $this->mParams['rows']
|
2013-04-13 23:06:43 +00:00
|
|
|
: static::DEFAULT_ROWS;
|
2009-10-09 14:22:37 +00:00
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-10-09 14:22:37 +00:00
|
|
|
function getInputHTML( $value ) {
|
|
|
|
|
$attribs = array(
|
|
|
|
|
'id' => $this->mID,
|
|
|
|
|
'name' => $this->mName,
|
|
|
|
|
'cols' => $this->getCols(),
|
|
|
|
|
'rows' => $this->getRows(),
|
2009-10-18 19:29:35 +00:00
|
|
|
) + $this->getTooltipAndAccessKey();
|
2009-10-09 14:22:37 +00:00
|
|
|
|
2011-12-21 01:10:51 +00:00
|
|
|
if ( $this->mClass !== '' ) {
|
|
|
|
|
$attribs['class'] = $this->mClass;
|
|
|
|
|
}
|
2012-05-04 22:09:33 +00:00
|
|
|
|
2009-10-09 14:22:37 +00:00
|
|
|
if ( !empty( $this->mParams['disabled'] ) ) {
|
|
|
|
|
$attribs['disabled'] = 'disabled';
|
|
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-10-09 14:22:37 +00:00
|
|
|
if ( !empty( $this->mParams['readonly'] ) ) {
|
|
|
|
|
$attribs['readonly'] = 'readonly';
|
|
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2012-04-20 23:18:50 +00:00
|
|
|
if ( isset( $this->mParams['placeholder'] ) ) {
|
2012-04-17 23:04:24 +00:00
|
|
|
$attribs['placeholder'] = $this->mParams['placeholder'];
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-19 01:24:58 +00:00
|
|
|
foreach ( array( 'required', 'autofocus' ) as $param ) {
|
|
|
|
|
if ( isset( $this->mParams[$param] ) ) {
|
|
|
|
|
$attribs[$param] = '';
|
2009-10-09 14:22:37 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Html::element( 'textarea', $attribs, $value );
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-04-24 01:31:17 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* A field that will contain a numeric value
|
|
|
|
|
*/
|
2009-07-17 22:19:02 +00:00
|
|
|
class HTMLFloatField extends HTMLTextField {
|
2009-04-24 01:31:17 +00:00
|
|
|
function getSize() {
|
2010-05-30 12:44:17 +00:00
|
|
|
return isset( $this->mParams['size'] )
|
|
|
|
|
? $this->mParams['size']
|
2009-09-28 19:04:10 +00:00
|
|
|
: 20;
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
function validate( $value, $alldata ) {
|
2009-06-21 18:26:29 +00:00
|
|
|
$p = parent::validate( $value, $alldata );
|
|
|
|
|
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( $p !== true ) {
|
|
|
|
|
return $p;
|
|
|
|
|
}
|
2011-03-05 12:48:32 +00:00
|
|
|
|
2010-12-12 15:32:29 +00:00
|
|
|
$value = trim( $value );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-12-12 15:32:29 +00:00
|
|
|
# http://dev.w3.org/html5/spec/common-microsyntaxes.html#real-numbers
|
2011-03-05 12:48:32 +00:00
|
|
|
# with the addition that a leading '+' sign is ok.
|
2010-12-15 13:33:47 +00:00
|
|
|
if ( !preg_match( '/^((\+|\-)?\d+(\.\d+)?(E(\+|\-)?\d+)?)?$/i', $value ) ) {
|
2012-08-23 07:11:21 +00:00
|
|
|
return $this->msg( 'htmlform-float-invalid' )->parseAsBlock();
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-05-30 12:44:17 +00:00
|
|
|
# The "int" part of these message names is rather confusing.
|
2009-09-28 19:04:10 +00:00
|
|
|
# They make equal sense for all numbers.
|
2009-06-21 18:26:29 +00:00
|
|
|
if ( isset( $this->mParams['min'] ) ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
$min = $this->mParams['min'];
|
2010-05-30 12:44:17 +00:00
|
|
|
|
|
|
|
|
if ( $min > $value ) {
|
2012-08-23 07:11:21 +00:00
|
|
|
return $this->msg( 'htmlform-int-toolow', $min )->parseAsBlock();
|
2010-05-30 12:44:17 +00:00
|
|
|
}
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
|
|
|
|
if ( isset( $this->mParams['max'] ) ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
$max = $this->mParams['max'];
|
2010-05-30 12:44:17 +00:00
|
|
|
|
|
|
|
|
if ( $max < $value ) {
|
2012-08-23 07:11:21 +00:00
|
|
|
return $this->msg( 'htmlform-int-toohigh', $max )->parseAsBlock();
|
2010-05-30 12:44:17 +00:00
|
|
|
}
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* A field that must contain a number
|
|
|
|
|
*/
|
2009-07-17 22:19:02 +00:00
|
|
|
class HTMLIntField extends HTMLFloatField {
|
|
|
|
|
function validate( $value, $alldata ) {
|
|
|
|
|
$p = parent::validate( $value, $alldata );
|
|
|
|
|
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( $p !== true ) {
|
|
|
|
|
return $p;
|
|
|
|
|
}
|
2009-07-17 22:19:02 +00:00
|
|
|
|
2010-12-12 15:32:29 +00:00
|
|
|
# http://dev.w3.org/html5/spec/common-microsyntaxes.html#signed-integers
|
2011-03-05 12:48:32 +00:00
|
|
|
# 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
|
2010-12-12 15:32:29 +00:00
|
|
|
# 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().
|
2010-12-15 13:33:47 +00:00
|
|
|
if ( !preg_match( '/^((\+|\-)?\d+)?$/', trim( $value ) )
|
2010-05-30 12:44:17 +00:00
|
|
|
) {
|
2012-08-23 07:11:21 +00:00
|
|
|
return $this->msg( 'htmlform-int-invalid' )->parseAsBlock();
|
2009-07-17 22:19:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* A checkbox field
|
|
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
class HTMLCheckField extends HTMLFormField {
|
|
|
|
|
function getInputHTML( $value ) {
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( !empty( $this->mParams['invert'] ) ) {
|
2009-04-27 00:55:23 +00:00
|
|
|
$value = !$value;
|
2010-05-30 12:44:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-05-30 12:44:17 +00:00
|
|
|
$attr = $this->getTooltipAndAccessKey();
|
2009-10-18 19:29:35 +00:00
|
|
|
$attr['id'] = $this->mID;
|
2010-05-30 12:44:17 +00:00
|
|
|
|
|
|
|
|
if ( !empty( $this->mParams['disabled'] ) ) {
|
2009-04-28 01:00:35 +00:00
|
|
|
$attr['disabled'] = 'disabled';
|
|
|
|
|
}
|
2012-05-04 22:09:33 +00:00
|
|
|
|
2011-12-21 01:10:51 +00:00
|
|
|
if ( $this->mClass !== '' ) {
|
|
|
|
|
$attr['class'] = $this->mClass;
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-05-30 17:33:59 +00:00
|
|
|
return Xml::check( $this->mName, $value, $attr ) . ' ' .
|
2010-05-30 12:44:17 +00:00
|
|
|
Html::rawElement( 'label', array( 'for' => $this->mID ), $this->mLabel );
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* For a checkbox, the label goes on the right hand side, and is
|
|
|
|
|
* added in getInputHTML(), rather than HTMLFormField::getRow()
|
2011-10-17 15:56:25 +00:00
|
|
|
* @return String
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2009-06-21 18:26:29 +00:00
|
|
|
function getLabel() {
|
2010-05-30 17:33:59 +00:00
|
|
|
return ' ';
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2011-04-23 21:27:24 +00:00
|
|
|
/**
|
|
|
|
|
* @param $request WebRequest
|
|
|
|
|
* @return String
|
|
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function loadDataFromRequest( $request ) {
|
|
|
|
|
$invert = false;
|
|
|
|
|
if ( isset( $this->mParams['invert'] ) && $this->mParams['invert'] ) {
|
|
|
|
|
$invert = true;
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
// GetCheck won't work like we want for checks.
|
2011-11-01 09:28:51 +00:00
|
|
|
// 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
|
2012-05-04 22:09:33 +00:00
|
|
|
if ( $request->getCheck( 'wpEditToken' ) || $request->getVal( $this->mName ) !== null ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
// 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;
|
|
|
|
|
} else {
|
|
|
|
|
return $this->getDefault();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-14 02:05:13 +00:00
|
|
|
/**
|
|
|
|
|
* A checkbox matrix
|
|
|
|
|
* Operates similarly to HTMLMultiSelectField, but instead of using an array of
|
|
|
|
|
* options, uses an array of rows and an array of columns to dynamically
|
2013-04-27 01:49:02 +00:00
|
|
|
* construct a matrix of options. The tags used to identify a particular cell
|
|
|
|
|
* are of the form "columnName-rowName"
|
|
|
|
|
*
|
|
|
|
|
* Options:
|
|
|
|
|
* columns: Required list of columns in the matrix.
|
|
|
|
|
* rows: Required list of rows in the matrix.
|
|
|
|
|
* force-options-on: Accepts array of column-row tags to be displayed as enabled
|
|
|
|
|
* but unavailable to change
|
|
|
|
|
* force-options-off: Accepts array of column-row tags to be displayed as disabled
|
|
|
|
|
* but unavailable to change.
|
2013-02-14 02:05:13 +00:00
|
|
|
*/
|
2013-04-27 01:49:02 +00:00
|
|
|
class HTMLCheckMatrix extends HTMLFormField implements HTMLNestedFilterable {
|
|
|
|
|
|
|
|
|
|
static private $requiredParams = array(
|
|
|
|
|
// Required by underlying HTMLFormField
|
|
|
|
|
'fieldname',
|
|
|
|
|
// Required by HTMLCheckMatrix
|
|
|
|
|
'rows', 'columns'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
public function __construct( $params ) {
|
|
|
|
|
$missing = array_diff( self::$requiredParams, array_keys( $params ) );
|
|
|
|
|
if ( $missing ) {
|
|
|
|
|
throw HTMLFormFieldRequiredOptionsException::create( $this, $missing );
|
|
|
|
|
}
|
|
|
|
|
parent::__construct( $params );
|
|
|
|
|
}
|
2013-02-14 02:05:13 +00:00
|
|
|
|
|
|
|
|
function validate( $value, $alldata ) {
|
|
|
|
|
$rows = $this->mParams['rows'];
|
|
|
|
|
$columns = $this->mParams['columns'];
|
|
|
|
|
|
|
|
|
|
// Make sure user-defined validation callback is run
|
|
|
|
|
$p = parent::validate( $value, $alldata );
|
|
|
|
|
if ( $p !== true ) {
|
|
|
|
|
return $p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make sure submitted value is an array
|
|
|
|
|
if ( !is_array( $value ) ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If all options are valid, array_intersect of the valid options
|
|
|
|
|
// and the provided options will return the provided options.
|
|
|
|
|
$validOptions = array();
|
|
|
|
|
foreach ( $rows as $rowTag ) {
|
|
|
|
|
foreach ( $columns as $columnTag ) {
|
|
|
|
|
$validOptions[] = $columnTag . '-' . $rowTag;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$validValues = array_intersect( $value, $validOptions );
|
|
|
|
|
if ( count( $validValues ) == count( $value ) ) {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
return $this->msg( 'htmlform-select-badoption' )->parse();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Build a table containing a matrix of checkbox options.
|
|
|
|
|
* The value of each option is a combination of the row tag and column tag.
|
|
|
|
|
* mParams['rows'] is an array with row labels as keys and row tags as values.
|
|
|
|
|
* mParams['columns'] is an array with column labels as keys and column tags as values.
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param array $value of the options that should be checked
|
2013-02-14 02:05:13 +00:00
|
|
|
* @return String
|
|
|
|
|
*/
|
|
|
|
|
function getInputHTML( $value ) {
|
|
|
|
|
$html = '';
|
|
|
|
|
$tableContents = '';
|
|
|
|
|
$attribs = array();
|
|
|
|
|
$rows = $this->mParams['rows'];
|
|
|
|
|
$columns = $this->mParams['columns'];
|
|
|
|
|
|
|
|
|
|
// If the disabled param is set, disable all the options
|
|
|
|
|
if ( !empty( $this->mParams['disabled'] ) ) {
|
|
|
|
|
$attribs['disabled'] = 'disabled';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Build the column headers
|
|
|
|
|
$headerContents = Html::rawElement( 'td', array(), ' ' );
|
|
|
|
|
foreach ( $columns as $columnLabel => $columnTag ) {
|
|
|
|
|
$headerContents .= Html::rawElement( 'td', array(), $columnLabel );
|
|
|
|
|
}
|
|
|
|
|
$tableContents .= Html::rawElement( 'tr', array(), "\n$headerContents\n" );
|
|
|
|
|
|
|
|
|
|
// Build the options matrix
|
|
|
|
|
foreach ( $rows as $rowLabel => $rowTag ) {
|
|
|
|
|
$rowContents = Html::rawElement( 'td', array(), $rowLabel );
|
|
|
|
|
foreach ( $columns as $columnTag ) {
|
2013-04-27 01:49:02 +00:00
|
|
|
$thisTag = "$columnTag-$rowTag";
|
|
|
|
|
// Construct the checkbox
|
|
|
|
|
$thisAttribs = array(
|
|
|
|
|
'id' => "{$this->mID}-$thisTag",
|
|
|
|
|
'value' => $thisTag,
|
|
|
|
|
);
|
|
|
|
|
$checked = in_array( $thisTag, (array)$value, true);
|
|
|
|
|
if ( $this->isTagForcedOff( $thisTag ) ) {
|
|
|
|
|
$checked = false;
|
|
|
|
|
$thisAttribs['disabled'] = 1;
|
|
|
|
|
} elseif ( $this->isTagForcedOn( $thisTag ) ) {
|
|
|
|
|
$checked = true;
|
|
|
|
|
$thisAttribs['disabled'] = 1;
|
2013-02-14 02:05:13 +00:00
|
|
|
}
|
2013-04-27 01:49:02 +00:00
|
|
|
$rowContents .= Html::rawElement(
|
|
|
|
|
'td',
|
|
|
|
|
array(),
|
|
|
|
|
Xml::check( "{$this->mName}[]", $checked, $attribs + $thisAttribs )
|
|
|
|
|
);
|
2013-02-14 02:05:13 +00:00
|
|
|
}
|
|
|
|
|
$tableContents .= Html::rawElement( 'tr', array(), "\n$rowContents\n" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Put it all in a table
|
|
|
|
|
$html .= Html::rawElement( 'table', array( 'class' => 'mw-htmlform-matrix' ),
|
|
|
|
|
Html::rawElement( 'tbody', array(), "\n$tableContents\n" ) ) . "\n";
|
|
|
|
|
|
|
|
|
|
return $html;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-27 01:49:02 +00:00
|
|
|
protected function isTagForcedOff( $tag ) {
|
|
|
|
|
return isset( $this->mParams['force-options-off'] )
|
|
|
|
|
&& in_array( $tag, $this->mParams['force-options-off'] );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function isTagForcedOn( $tag ) {
|
|
|
|
|
return isset( $this->mParams['force-options-on'] )
|
|
|
|
|
&& in_array( $tag, $this->mParams['force-options-on'] );
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-14 02:05:13 +00:00
|
|
|
/**
|
|
|
|
|
* Get the complete table row for the input, including help text,
|
|
|
|
|
* labels, and whatever.
|
|
|
|
|
* We override this function since the label should always be on a separate
|
|
|
|
|
* line above the options in the case of a checkbox matrix, i.e. it's always
|
|
|
|
|
* a "vertical-label".
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $value the value to set the input to
|
2013-02-14 02:05:13 +00:00
|
|
|
* @return String complete HTML table row
|
|
|
|
|
*/
|
|
|
|
|
function getTableRow( $value ) {
|
|
|
|
|
list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value );
|
|
|
|
|
$inputHtml = $this->getInputHTML( $value );
|
|
|
|
|
$fieldType = get_class( $this );
|
|
|
|
|
$helptext = $this->getHelpTextHtmlTable( $this->getHelpText() );
|
|
|
|
|
$cellAttributes = array( 'colspan' => 2 );
|
|
|
|
|
|
|
|
|
|
$label = $this->getLabelHtml( $cellAttributes );
|
|
|
|
|
|
|
|
|
|
$field = Html::rawElement(
|
|
|
|
|
'td',
|
|
|
|
|
array( 'class' => 'mw-input' ) + $cellAttributes,
|
|
|
|
|
$inputHtml . "\n$errors"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$html = Html::rawElement( 'tr',
|
|
|
|
|
array( 'class' => 'mw-htmlform-vertical-label' ), $label );
|
|
|
|
|
$html .= Html::rawElement( 'tr',
|
|
|
|
|
array( 'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass" ),
|
|
|
|
|
$field );
|
|
|
|
|
|
|
|
|
|
return $html . $helptext;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param $request WebRequest
|
|
|
|
|
* @return Array
|
|
|
|
|
*/
|
|
|
|
|
function loadDataFromRequest( $request ) {
|
|
|
|
|
if ( $this->mParent->getMethod() == 'post' ) {
|
|
|
|
|
if ( $request->wasPosted() ) {
|
|
|
|
|
// Checkboxes are not added to the request arrays if they're not checked,
|
|
|
|
|
// so it's perfectly possible for there not to be an entry at all
|
|
|
|
|
return $request->getArray( $this->mName, array() );
|
|
|
|
|
} else {
|
|
|
|
|
// That's ok, the user has not yet submitted the form, so show the defaults
|
|
|
|
|
return $this->getDefault();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// This is the impossible case: if we look at $_GET and see no data for our
|
|
|
|
|
// field, is it because the user has not yet submitted the form, or that they
|
|
|
|
|
// have submitted it with all the options unchecked. We will have to assume the
|
|
|
|
|
// latter, which basically means that you can't specify 'positive' defaults
|
|
|
|
|
// for GET forms.
|
|
|
|
|
return $request->getArray( $this->mName, array() );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getDefault() {
|
|
|
|
|
if ( isset( $this->mDefault ) ) {
|
|
|
|
|
return $this->mDefault;
|
|
|
|
|
} else {
|
|
|
|
|
return array();
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-04-27 01:49:02 +00:00
|
|
|
|
|
|
|
|
function filterDataForSubmit( $data ) {
|
|
|
|
|
$columns = HTMLFormField::flattenOptions( $this->mParams['columns'] );
|
|
|
|
|
$rows = HTMLFormField::flattenOptions( $this->mParams['rows'] );
|
|
|
|
|
$res = array();
|
|
|
|
|
foreach ( $columns as $column ) {
|
|
|
|
|
foreach ( $rows as $row ) {
|
|
|
|
|
// Make sure option hasn't been forced
|
|
|
|
|
$thisTag = "$column-$row";
|
|
|
|
|
if ( $this->isTagForcedOff( $thisTag ) ) {
|
|
|
|
|
$res[$thisTag] = false;
|
|
|
|
|
} elseif ($this->isTagForcedOn( $thisTag ) ) {
|
|
|
|
|
$res[$thisTag] = true;
|
|
|
|
|
} else {
|
|
|
|
|
$res[$thisTag] = in_array( $thisTag, $data );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $res;
|
|
|
|
|
}
|
2013-02-14 02:05:13 +00:00
|
|
|
}
|
|
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* A select dropdown field. Basically a wrapper for Xmlselect class
|
|
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
class HTMLSelectField extends HTMLFormField {
|
|
|
|
|
function validate( $value, $alldata ) {
|
|
|
|
|
$p = parent::validate( $value, $alldata );
|
2010-05-30 12:44:17 +00:00
|
|
|
|
|
|
|
|
if ( $p !== true ) {
|
|
|
|
|
return $p;
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
$validOptions = HTMLFormField::flattenOptions( $this->mParams['options'] );
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2013-04-20 22:49:30 +00:00
|
|
|
if ( in_array( $value, $validOptions ) ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
return true;
|
2013-04-20 22:49:30 +00:00
|
|
|
} else {
|
2012-08-23 07:11:21 +00:00
|
|
|
return $this->msg( 'htmlform-select-badoption' )->parse();
|
2013-04-20 22:49:30 +00:00
|
|
|
}
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
|
|
|
|
function getInputHTML( $value ) {
|
|
|
|
|
$select = new XmlSelect( $this->mName, $this->mID, strval( $value ) );
|
|
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
# If one of the options' 'name' is int(0), it is automatically selected.
|
2011-04-13 16:51:22 +00:00
|
|
|
# because PHP sucks and thinks int(0) == 'some string'.
|
2009-09-28 19:04:10 +00:00
|
|
|
# Working around this by forcing all of them to strings.
|
2012-05-04 22:09:33 +00:00
|
|
|
foreach ( $this->mParams['options'] as &$opt ) {
|
|
|
|
|
if ( is_int( $opt ) ) {
|
2010-12-18 19:08:22 +00:00
|
|
|
$opt = strval( $opt );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
unset( $opt ); # PHP keeps $opt around as a reference, which is a bit scary
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( !empty( $this->mParams['disabled'] ) ) {
|
2009-04-28 01:00:35 +00:00
|
|
|
$select->setAttribute( 'disabled', 'disabled' );
|
|
|
|
|
}
|
2012-05-04 22:09:33 +00:00
|
|
|
|
2011-12-21 01:10:51 +00:00
|
|
|
if ( $this->mClass !== '' ) {
|
|
|
|
|
$select->setAttribute( 'class', $this->mClass );
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-12-18 19:08:22 +00:00
|
|
|
$select->addOptions( $this->mParams['options'] );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
return $select->getHTML();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Select dropdown field, with an additional "other" textbox.
|
|
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
class HTMLSelectOrOtherField extends HTMLTextField {
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
function __construct( $params ) {
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( !in_array( 'other', $params['options'], true ) ) {
|
2012-08-19 20:44:29 +00:00
|
|
|
$msg = isset( $params['other'] ) ?
|
|
|
|
|
$params['other'] :
|
|
|
|
|
wfMessage( 'htmlform-selectorother-other' )->text();
|
2011-07-09 19:33:58 +00:00
|
|
|
$params['options'][$msg] = 'other';
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
parent::__construct( $params );
|
|
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-07-29 16:20:10 +00:00
|
|
|
static function forceToStringRecursive( $array ) {
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( is_array( $array ) ) {
|
|
|
|
|
return array_map( array( __CLASS__, 'forceToStringRecursive' ), $array );
|
2009-07-29 16:20:10 +00:00
|
|
|
} else {
|
2010-05-30 12:44:17 +00:00
|
|
|
return strval( $array );
|
2009-07-29 16:20:10 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
function getInputHTML( $value ) {
|
|
|
|
|
$valInSelect = false;
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( $value !== false ) {
|
|
|
|
|
$valInSelect = in_array(
|
|
|
|
|
$value,
|
|
|
|
|
HTMLFormField::flattenOptions( $this->mParams['options'] )
|
|
|
|
|
);
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
$selected = $valInSelect ? $value : 'other';
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-07-29 16:20:10 +00:00
|
|
|
$opts = self::forceToStringRecursive( $this->mParams['options'] );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
$select = new XmlSelect( $this->mName, $this->mID, $selected );
|
2009-07-29 16:20:10 +00:00
|
|
|
$select->addOptions( $opts );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
$select->setAttribute( 'class', 'mw-htmlform-select-or-other' );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-11 15:53:48 +00:00
|
|
|
$tbAttribs = array( 'id' => $this->mID . '-other', 'size' => $this->getSize() );
|
2010-05-30 12:44:17 +00:00
|
|
|
|
|
|
|
|
if ( !empty( $this->mParams['disabled'] ) ) {
|
2009-04-28 01:00:35 +00:00
|
|
|
$select->setAttribute( 'disabled', 'disabled' );
|
|
|
|
|
$tbAttribs['disabled'] = 'disabled';
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-28 01:00:35 +00:00
|
|
|
$select = $select->getHTML();
|
2009-06-21 18:26:29 +00:00
|
|
|
|
|
|
|
|
if ( isset( $this->mParams['maxlength'] ) ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
$tbAttribs['maxlength'] = $this->mParams['maxlength'];
|
|
|
|
|
}
|
2012-05-04 22:09:33 +00:00
|
|
|
|
2011-12-21 01:10:51 +00:00
|
|
|
if ( $this->mClass !== '' ) {
|
|
|
|
|
$tbAttribs['class'] = $this->mClass;
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-05-30 12:44:17 +00:00
|
|
|
$textbox = Html::input(
|
|
|
|
|
$this->mName . '-other',
|
|
|
|
|
$valInSelect ? '' : $value,
|
|
|
|
|
'text',
|
|
|
|
|
$tbAttribs
|
|
|
|
|
);
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-11-14 20:59:15 +00:00
|
|
|
return "$select<br />\n$textbox";
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2011-04-23 21:27:24 +00:00
|
|
|
/**
|
|
|
|
|
* @param $request WebRequest
|
|
|
|
|
* @return String
|
|
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function loadDataFromRequest( $request ) {
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( $request->getCheck( $this->mName ) ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
$val = $request->getText( $this->mName );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( $val == 'other' ) {
|
2009-06-21 18:26:29 +00:00
|
|
|
$val = $request->getText( $this->mName . '-other' );
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
return $val;
|
|
|
|
|
} else {
|
|
|
|
|
return $this->getDefault();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Multi-select field
|
|
|
|
|
*/
|
2013-04-27 01:49:02 +00:00
|
|
|
class HTMLMultiSelectField extends HTMLFormField implements HTMLNestedFilterable {
|
2011-03-27 22:45:32 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
function validate( $value, $alldata ) {
|
|
|
|
|
$p = parent::validate( $value, $alldata );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( $p !== true ) {
|
|
|
|
|
return $p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( !is_array( $value ) ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-05-30 12:44:17 +00:00
|
|
|
# If all options are valid, array_intersect of the valid options
|
2009-09-28 19:04:10 +00:00
|
|
|
# and the provided options will return the provided options.
|
2009-04-24 01:31:17 +00:00
|
|
|
$validOptions = HTMLFormField::flattenOptions( $this->mParams['options'] );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
$validValues = array_intersect( $value, $validOptions );
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( count( $validValues ) == count( $value ) ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
return true;
|
2010-05-30 12:44:17 +00:00
|
|
|
} else {
|
2012-08-23 07:11:21 +00:00
|
|
|
return $this->msg( 'htmlform-select-badoption' )->parse();
|
2010-05-30 12:44:17 +00:00
|
|
|
}
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
function getInputHTML( $value ) {
|
|
|
|
|
$html = $this->formatOptions( $this->mParams['options'], $value );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
return $html;
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
function formatOptions( $options, $value ) {
|
|
|
|
|
$html = '';
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-28 01:00:35 +00:00
|
|
|
$attribs = array();
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-04-28 01:00:35 +00:00
|
|
|
if ( !empty( $this->mParams['disabled'] ) ) {
|
|
|
|
|
$attribs['disabled'] = 'disabled';
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-05-30 12:44:17 +00:00
|
|
|
foreach ( $options as $label => $info ) {
|
|
|
|
|
if ( is_array( $info ) ) {
|
2009-09-07 01:47:45 +00:00
|
|
|
$html .= Html::rawElement( 'h1', array(), $label ) . "\n";
|
2009-04-24 01:31:17 +00:00
|
|
|
$html .= $this->formatOptions( $info, $value );
|
|
|
|
|
} else {
|
2010-12-12 15:32:29 +00:00
|
|
|
$thisAttribs = array( 'id' => "{$this->mID}-$info", 'value' => $info );
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2011-03-05 12:48:32 +00:00
|
|
|
$checkbox = Xml::check(
|
|
|
|
|
$this->mName . '[]',
|
2010-12-12 15:32:29 +00:00
|
|
|
in_array( $info, $value, true ),
|
|
|
|
|
$attribs + $thisAttribs );
|
|
|
|
|
$checkbox .= ' ' . Html::rawElement( 'label', array( 'for' => "{$this->mID}-$info" ), $label );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2011-12-23 20:35:57 +00:00
|
|
|
$html .= ' ' . Html::rawElement( 'div', array( 'class' => 'mw-htmlform-flatlist-item' ), $checkbox );
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
return $html;
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2011-04-23 21:27:24 +00:00
|
|
|
/**
|
|
|
|
|
* @param $request WebRequest
|
|
|
|
|
* @return String
|
|
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function loadDataFromRequest( $request ) {
|
2011-03-14 15:50:26 +00:00
|
|
|
if ( $this->mParent->getMethod() == 'post' ) {
|
2012-05-04 22:09:33 +00:00
|
|
|
if ( $request->wasPosted() ) {
|
2011-03-14 15:50:26 +00:00
|
|
|
# Checkboxes are just not added to the request arrays if they're not checked,
|
|
|
|
|
# so it's perfectly possible for there not to be an entry at all
|
|
|
|
|
return $request->getArray( $this->mName, array() );
|
|
|
|
|
} else {
|
|
|
|
|
# That's ok, the user has not yet submitted the form, so show the defaults
|
|
|
|
|
return $this->getDefault();
|
2010-05-30 12:44:17 +00:00
|
|
|
}
|
2009-04-24 01:31:17 +00:00
|
|
|
} else {
|
2011-03-14 15:50:26 +00:00
|
|
|
# This is the impossible case: if we look at $_GET and see no data for our
|
|
|
|
|
# field, is it because the user has not yet submitted the form, or that they
|
|
|
|
|
# have submitted it with all the options unchecked? We will have to assume the
|
|
|
|
|
# latter, which basically means that you can't specify 'positive' defaults
|
2011-05-17 22:03:20 +00:00
|
|
|
# for GET forms.
|
|
|
|
|
# @todo FIXME...
|
2011-03-14 15:50:26 +00:00
|
|
|
return $request->getArray( $this->mName, array() );
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
function getDefault() {
|
|
|
|
|
if ( isset( $this->mDefault ) ) {
|
|
|
|
|
return $this->mDefault;
|
|
|
|
|
} else {
|
|
|
|
|
return array();
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-09-07 01:48:06 +00:00
|
|
|
|
2013-04-27 01:49:02 +00:00
|
|
|
function filterDataForSubmit( $data ) {
|
|
|
|
|
$options = HTMLFormField::flattenOptions( $this->mParams['options'] );
|
|
|
|
|
|
|
|
|
|
$res = array();
|
|
|
|
|
foreach ( $options as $opt ) {
|
|
|
|
|
$res["$opt"] = in_array( $opt, $data );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $res;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-07 01:48:06 +00:00
|
|
|
protected function needsLabel() {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
|
|
|
|
|
2011-03-05 16:51:13 +00:00
|
|
|
/**
|
|
|
|
|
* Double field with a dropdown list constructed from a system message in the format
|
|
|
|
|
* * Optgroup header
|
2011-09-22 22:10:41 +00:00
|
|
|
* ** <option value>
|
2011-03-05 16:51:13 +00:00
|
|
|
* * New Optgroup header
|
|
|
|
|
* Plus a text field underneath for an additional reason. The 'value' of the field is
|
2012-07-10 12:48:06 +00:00
|
|
|
* "<select>: <extra reason>", or "<extra reason>" if nothing has been selected in the
|
2011-03-05 16:51:13 +00:00
|
|
|
* select dropdown.
|
2011-05-17 22:03:20 +00:00
|
|
|
* @todo FIXME: If made 'required', only the text field should be compulsory.
|
2011-03-05 16:51:13 +00:00
|
|
|
*/
|
|
|
|
|
class HTMLSelectAndOtherField extends HTMLSelectField {
|
|
|
|
|
|
|
|
|
|
function __construct( $params ) {
|
|
|
|
|
if ( array_key_exists( 'other', $params ) ) {
|
2012-05-04 22:09:33 +00:00
|
|
|
} elseif ( array_key_exists( 'other-message', $params ) ) {
|
2011-09-22 22:10:41 +00:00
|
|
|
$params['other'] = wfMessage( $params['other-message'] )->plain();
|
2011-03-05 16:51:13 +00:00
|
|
|
} else {
|
2011-06-27 18:05:09 +00:00
|
|
|
$params['other'] = null;
|
2011-03-05 16:51:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( array_key_exists( 'options', $params ) ) {
|
|
|
|
|
# Options array already specified
|
2012-05-04 22:09:33 +00:00
|
|
|
} elseif ( array_key_exists( 'options-message', $params ) ) {
|
2011-03-05 16:51:13 +00:00
|
|
|
# Generate options array from a system message
|
2011-06-27 18:05:09 +00:00
|
|
|
$params['options'] = self::parseMessage(
|
2011-09-22 22:10:41 +00:00
|
|
|
wfMessage( $params['options-message'] )->inContentLanguage()->plain(),
|
2011-06-27 18:05:09 +00:00
|
|
|
$params['other']
|
|
|
|
|
);
|
2011-03-05 16:51:13 +00:00
|
|
|
} else {
|
|
|
|
|
# Sulk
|
|
|
|
|
throw new MWException( 'HTMLSelectAndOtherField called without any options' );
|
|
|
|
|
}
|
|
|
|
|
$this->mFlatOptions = self::flattenOptions( $params['options'] );
|
|
|
|
|
|
|
|
|
|
parent::__construct( $params );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Build a drop-down box from a textual list.
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $string message text
|
|
|
|
|
* @param string $otherName name of "other reason" option
|
2011-03-05 16:51:13 +00:00
|
|
|
* @return Array
|
|
|
|
|
* TODO: this is copied from Xml::listDropDown(), deprecate/avoid duplication?
|
|
|
|
|
*/
|
2012-05-04 22:09:33 +00:00
|
|
|
public static function parseMessage( $string, $otherName = null ) {
|
|
|
|
|
if ( $otherName === null ) {
|
2011-09-22 22:10:41 +00:00
|
|
|
$otherName = wfMessage( 'htmlform-selectorother-other' )->plain();
|
2011-03-05 16:51:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$optgroup = false;
|
|
|
|
|
$options = array( $otherName => 'other' );
|
|
|
|
|
|
|
|
|
|
foreach ( explode( "\n", $string ) as $option ) {
|
|
|
|
|
$value = trim( $option );
|
|
|
|
|
if ( $value == '' ) {
|
|
|
|
|
continue;
|
2012-05-04 22:09:33 +00:00
|
|
|
} elseif ( substr( $value, 0, 1 ) == '*' && substr( $value, 1, 1 ) != '*' ) {
|
2011-03-05 16:51:13 +00:00
|
|
|
# A new group is starting...
|
|
|
|
|
$value = trim( substr( $value, 1 ) );
|
|
|
|
|
$optgroup = $value;
|
2012-05-04 22:09:33 +00:00
|
|
|
} elseif ( substr( $value, 0, 2 ) == '**' ) {
|
2011-03-05 16:51:13 +00:00
|
|
|
# groupmember
|
|
|
|
|
$opt = trim( substr( $value, 2 ) );
|
2012-05-04 22:09:33 +00:00
|
|
|
if ( $optgroup === false ) {
|
2011-09-22 22:10:41 +00:00
|
|
|
$options[$opt] = $opt;
|
2011-03-05 16:51:13 +00:00
|
|
|
} else {
|
2011-09-22 22:10:41 +00:00
|
|
|
$options[$optgroup][$opt] = $opt;
|
2011-03-05 16:51:13 +00:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
# groupless reason list
|
|
|
|
|
$optgroup = false;
|
2011-09-22 22:10:41 +00:00
|
|
|
$options[$option] = $option;
|
2011-03-05 16:51:13 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $options;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getInputHTML( $value ) {
|
2011-03-12 11:08:20 +00:00
|
|
|
$select = parent::getInputHTML( $value[1] );
|
2011-03-05 16:51:13 +00:00
|
|
|
|
|
|
|
|
$textAttribs = array(
|
|
|
|
|
'id' => $this->mID . '-other',
|
|
|
|
|
'size' => $this->getSize(),
|
|
|
|
|
);
|
2012-05-04 22:09:33 +00:00
|
|
|
|
2011-12-21 01:10:51 +00:00
|
|
|
if ( $this->mClass !== '' ) {
|
|
|
|
|
$textAttribs['class'] = $this->mClass;
|
|
|
|
|
}
|
2011-03-05 16:51:13 +00:00
|
|
|
|
|
|
|
|
foreach ( array( 'required', 'autofocus', 'multiple', 'disabled' ) as $param ) {
|
|
|
|
|
if ( isset( $this->mParams[$param] ) ) {
|
|
|
|
|
$textAttribs[$param] = '';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$textbox = Html::input(
|
|
|
|
|
$this->mName . '-other',
|
2011-03-12 11:08:20 +00:00
|
|
|
$value[2],
|
2011-03-05 16:51:13 +00:00
|
|
|
'text',
|
|
|
|
|
$textAttribs
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return "$select<br />\n$textbox";
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-12 11:08:20 +00:00
|
|
|
/**
|
|
|
|
|
* @param $request WebRequest
|
2012-07-15 20:32:48 +00:00
|
|
|
* @return Array("<overall message>","<select value>","<text field value>")
|
2011-03-12 11:08:20 +00:00
|
|
|
*/
|
2011-03-05 16:51:13 +00:00
|
|
|
function loadDataFromRequest( $request ) {
|
|
|
|
|
if ( $request->getCheck( $this->mName ) ) {
|
|
|
|
|
|
|
|
|
|
$list = $request->getText( $this->mName );
|
|
|
|
|
$text = $request->getText( $this->mName . '-other' );
|
|
|
|
|
|
|
|
|
|
if ( $list == 'other' ) {
|
2011-03-12 11:08:20 +00:00
|
|
|
$final = $text;
|
2012-05-04 22:09:33 +00:00
|
|
|
} elseif ( !in_array( $list, $this->mFlatOptions ) ) {
|
2011-03-12 11:08:20 +00:00
|
|
|
# User has spoofed the select form to give an option which wasn't
|
|
|
|
|
# in the original offer. Sulk...
|
|
|
|
|
$final = $text;
|
2012-05-04 22:09:33 +00:00
|
|
|
} elseif ( $text == '' ) {
|
2011-03-12 11:08:20 +00:00
|
|
|
$final = $list;
|
2011-03-05 16:51:13 +00:00
|
|
|
} else {
|
2012-08-23 07:11:21 +00:00
|
|
|
$final = $list . $this->msg( 'colon-separator' )->inContentLanguage()->text() . $text;
|
2011-03-05 16:51:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
2011-03-12 11:08:20 +00:00
|
|
|
$final = $this->getDefault();
|
2011-10-17 16:16:26 +00:00
|
|
|
|
|
|
|
|
$list = 'other';
|
|
|
|
|
$text = $final;
|
|
|
|
|
foreach ( $this->mFlatOptions as $option ) {
|
2012-08-23 07:11:21 +00:00
|
|
|
$match = $option . $this->msg( 'colon-separator' )->inContentLanguage()->text();
|
2012-05-04 22:09:33 +00:00
|
|
|
if ( strpos( $text, $match ) === 0 ) {
|
2011-10-17 16:16:26 +00:00
|
|
|
$list = $option;
|
|
|
|
|
$text = substr( $text, strlen( $match ) );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-03-05 16:51:13 +00:00
|
|
|
}
|
2011-03-12 11:08:20 +00:00
|
|
|
return array( $final, $list, $text );
|
2011-03-05 16:51:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getSize() {
|
|
|
|
|
return isset( $this->mParams['size'] )
|
|
|
|
|
? $this->mParams['size']
|
|
|
|
|
: 45;
|
|
|
|
|
}
|
2011-03-12 11:08:20 +00:00
|
|
|
|
|
|
|
|
function validate( $value, $alldata ) {
|
|
|
|
|
# HTMLSelectField forces $value to be one of the options in the select
|
|
|
|
|
# field, which is not useful here. But we do want the validation further up
|
|
|
|
|
# the chain
|
|
|
|
|
$p = parent::validate( $value[1], $alldata );
|
|
|
|
|
|
|
|
|
|
if ( $p !== true ) {
|
|
|
|
|
return $p;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-11 22:23:46 +00:00
|
|
|
if ( isset( $this->mParams['required'] ) && $this->mParams['required'] !== false && $value[1] === '' ) {
|
2012-08-23 07:11:21 +00:00
|
|
|
return $this->msg( 'htmlform-required' )->parse();
|
2011-03-12 11:08:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2011-03-05 16:51:13 +00:00
|
|
|
}
|
|
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* Radio checkbox fields.
|
|
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
class HTMLRadioField extends HTMLFormField {
|
2011-10-23 16:57:53 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
function validate( $value, $alldata ) {
|
|
|
|
|
$p = parent::validate( $value, $alldata );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( $p !== true ) {
|
|
|
|
|
return $p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( !is_string( $value ) && !is_int( $value ) ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
return false;
|
2010-05-30 12:44:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
$validOptions = HTMLFormField::flattenOptions( $this->mParams['options'] );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( in_array( $value, $validOptions ) ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
return true;
|
2010-05-30 12:44:17 +00:00
|
|
|
} else {
|
2012-08-23 07:11:21 +00:00
|
|
|
return $this->msg( 'htmlform-select-badoption' )->parse();
|
2010-05-30 12:44:17 +00:00
|
|
|
}
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* This returns a block of all the radio options, in one cell.
|
|
|
|
|
* @see includes/HTMLFormField#getInputHTML()
|
2011-10-17 15:56:25 +00:00
|
|
|
* @param $value String
|
|
|
|
|
* @return String
|
2009-09-28 19:04:10 +00:00
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
function getInputHTML( $value ) {
|
|
|
|
|
$html = $this->formatOptions( $this->mParams['options'], $value );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
return $html;
|
|
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
function formatOptions( $options, $value ) {
|
|
|
|
|
$html = '';
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-28 01:00:35 +00:00
|
|
|
$attribs = array();
|
|
|
|
|
if ( !empty( $this->mParams['disabled'] ) ) {
|
|
|
|
|
$attribs['disabled'] = 'disabled';
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
# TODO: should this produce an unordered list perhaps?
|
2010-05-30 12:44:17 +00:00
|
|
|
foreach ( $options as $label => $info ) {
|
|
|
|
|
if ( is_array( $info ) ) {
|
2009-09-07 01:47:45 +00:00
|
|
|
$html .= Html::rawElement( 'h1', array(), $label ) . "\n";
|
2009-04-24 01:31:17 +00:00
|
|
|
$html .= $this->formatOptions( $info, $value );
|
|
|
|
|
} else {
|
2009-07-19 16:49:58 +00:00
|
|
|
$id = Sanitizer::escapeId( $this->mID . "-$info" );
|
2011-10-23 16:57:53 +00:00
|
|
|
$radio = Xml::radio(
|
2010-05-30 12:44:17 +00:00
|
|
|
$this->mName,
|
|
|
|
|
$info,
|
|
|
|
|
$info == $value,
|
|
|
|
|
$attribs + array( 'id' => $id )
|
|
|
|
|
);
|
2011-10-23 16:57:53 +00:00
|
|
|
$radio .= ' ' .
|
2009-09-07 01:47:45 +00:00
|
|
|
Html::rawElement( 'label', array( 'for' => $id ), $label );
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2011-12-23 20:35:57 +00:00
|
|
|
$html .= ' ' . Html::rawElement( 'div', array( 'class' => 'mw-htmlform-flatlist-item' ), $radio );
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
return $html;
|
|
|
|
|
}
|
2009-09-07 01:48:06 +00:00
|
|
|
|
|
|
|
|
protected function needsLabel() {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
|
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
/**
|
|
|
|
|
* An information field (text blob), not a proper input.
|
|
|
|
|
*/
|
2009-04-24 01:31:17 +00:00
|
|
|
class HTMLInfoField extends HTMLFormField {
|
2012-05-04 22:09:33 +00:00
|
|
|
public function __construct( $info ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
$info['nodata'] = true;
|
2009-06-21 18:26:29 +00:00
|
|
|
|
|
|
|
|
parent::__construct( $info );
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2012-05-04 22:09:33 +00:00
|
|
|
public function getInputHTML( $value ) {
|
2009-06-21 18:26:29 +00:00
|
|
|
return !empty( $this->mParams['raw'] ) ? $value : htmlspecialchars( $value );
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2012-05-04 22:09:33 +00:00
|
|
|
public function getTableRow( $value ) {
|
2009-06-21 18:26:29 +00:00
|
|
|
if ( !empty( $this->mParams['rawrow'] ) ) {
|
2009-04-24 01:31:17 +00:00
|
|
|
return $value;
|
|
|
|
|
}
|
2009-06-21 18:26:29 +00:00
|
|
|
|
2009-04-24 01:31:17 +00:00
|
|
|
return parent::getTableRow( $value );
|
|
|
|
|
}
|
2009-09-07 01:48:06 +00:00
|
|
|
|
2012-05-04 22:09:33 +00:00
|
|
|
/**
|
|
|
|
|
* @since 1.20
|
|
|
|
|
*/
|
|
|
|
|
public function getDiv( $value ) {
|
|
|
|
|
if ( !empty( $this->mParams['rawrow'] ) ) {
|
|
|
|
|
return $value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return parent::getDiv( $value );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @since 1.20
|
|
|
|
|
*/
|
|
|
|
|
public function getRaw( $value ) {
|
|
|
|
|
if ( !empty( $this->mParams['rawrow'] ) ) {
|
|
|
|
|
return $value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return parent::getRaw( $value );
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-07 01:48:06 +00:00
|
|
|
protected function needsLabel() {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2009-04-24 01:31:17 +00:00
|
|
|
}
|
2009-09-28 19:04:10 +00:00
|
|
|
|
|
|
|
|
class HTMLHiddenField extends HTMLFormField {
|
2010-05-30 12:44:17 +00:00
|
|
|
public function __construct( $params ) {
|
2010-04-14 21:42:37 +00:00
|
|
|
parent::__construct( $params );
|
2011-03-05 12:48:32 +00:00
|
|
|
|
2010-12-12 15:32:29 +00:00
|
|
|
# Per HTML5 spec, hidden fields cannot be 'required'
|
|
|
|
|
# http://dev.w3.org/html5/spec/states-of-the-type-attribute.html#hidden-state
|
|
|
|
|
unset( $this->mParams['required'] );
|
2010-04-14 21:42:37 +00:00
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
|
|
|
|
public function getTableRow( $value ) {
|
2010-04-10 12:03:30 +00:00
|
|
|
$params = array();
|
2010-05-30 12:44:17 +00:00
|
|
|
if ( $this->mID ) {
|
2010-04-10 12:03:30 +00:00
|
|
|
$params['id'] = $this->mID;
|
|
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
|
|
|
|
$this->mParent->addHiddenField(
|
2010-04-10 12:03:30 +00:00
|
|
|
$this->mName,
|
2011-10-22 20:10:41 +00:00
|
|
|
$this->mDefault,
|
2010-04-10 12:03:30 +00:00
|
|
|
$params
|
2009-09-28 19:04:10 +00:00
|
|
|
);
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-09-28 19:04:10 +00:00
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-04 22:09:33 +00:00
|
|
|
/**
|
|
|
|
|
* @since 1.20
|
|
|
|
|
*/
|
|
|
|
|
public function getDiv( $value ) {
|
|
|
|
|
return $this->getTableRow( $value );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @since 1.20
|
|
|
|
|
*/
|
|
|
|
|
public function getRaw( $value ) {
|
|
|
|
|
return $this->getTableRow( $value );
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-20 22:49:30 +00:00
|
|
|
public function getInputHTML( $value ) {
|
|
|
|
|
return '';
|
|
|
|
|
}
|
2009-09-28 19:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
2010-03-13 15:33:18 +00:00
|
|
|
/**
|
2010-05-30 12:44:17 +00:00
|
|
|
* Add a submit button inline in the form (as opposed to
|
2010-03-13 15:33:18 +00:00
|
|
|
* HTMLForm::addButton(), which will add it at the end).
|
|
|
|
|
*/
|
2013-03-21 00:54:32 +00:00
|
|
|
class HTMLSubmitField extends HTMLButtonField {
|
|
|
|
|
protected $buttonType = 'submit';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Adds a generic button inline to the form. Does not do anything, you must add
|
|
|
|
|
* click handling code in JavaScript. Use a HTMLSubmitField if you merely
|
|
|
|
|
* wish to add a submit button to a form.
|
|
|
|
|
*
|
|
|
|
|
* @since 1.22
|
|
|
|
|
*/
|
|
|
|
|
class HTMLButtonField extends HTMLFormField {
|
|
|
|
|
protected $buttonType = 'button';
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2012-05-04 22:09:33 +00:00
|
|
|
public function __construct( $info ) {
|
2010-03-13 15:33:18 +00:00
|
|
|
$info['nodata'] = true;
|
|
|
|
|
parent::__construct( $info );
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-04 22:09:33 +00:00
|
|
|
public function getInputHTML( $value ) {
|
2013-03-09 01:30:49 +00:00
|
|
|
$attr = array(
|
|
|
|
|
'class' => 'mw-htmlform-submit ' . $this->mClass,
|
|
|
|
|
'id' => $this->mID,
|
2009-09-28 19:04:10 +00:00
|
|
|
);
|
2013-03-09 01:30:49 +00:00
|
|
|
|
|
|
|
|
if ( !empty( $this->mParams['disabled'] ) ) {
|
|
|
|
|
$attr['disabled'] = 'disabled';
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-21 00:54:32 +00:00
|
|
|
return Html::input(
|
|
|
|
|
$this->mName,
|
|
|
|
|
$value,
|
|
|
|
|
$this->buttonType,
|
|
|
|
|
$attr
|
|
|
|
|
);
|
2009-09-28 19:04:10 +00:00
|
|
|
}
|
2010-03-13 15:33:18 +00:00
|
|
|
|
|
|
|
|
protected function needsLabel() {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2011-03-05 12:48:32 +00:00
|
|
|
|
2010-12-12 15:32:29 +00:00
|
|
|
/**
|
|
|
|
|
* Button cannot be invalid
|
2011-10-17 15:56:25 +00:00
|
|
|
* @param $value String
|
|
|
|
|
* @param $alldata Array
|
|
|
|
|
* @return Bool
|
2010-12-12 15:32:29 +00:00
|
|
|
*/
|
2012-05-04 22:09:33 +00:00
|
|
|
public function validate( $value, $alldata ) {
|
2010-12-12 15:32:29 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
2009-10-18 19:29:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class HTMLEditTools extends HTMLFormField {
|
|
|
|
|
public function getInputHTML( $value ) {
|
|
|
|
|
return '';
|
|
|
|
|
}
|
2010-05-30 12:44:17 +00:00
|
|
|
|
2009-10-18 19:29:35 +00:00
|
|
|
public function getTableRow( $value ) {
|
2012-05-04 22:09:33 +00:00
|
|
|
$msg = $this->formatMsg();
|
|
|
|
|
|
|
|
|
|
return '<tr><td></td><td class="mw-input">'
|
|
|
|
|
. '<div class="mw-editTools">'
|
|
|
|
|
. $msg->parseAsBlock()
|
|
|
|
|
. "</div></td></tr>\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @since 1.20
|
|
|
|
|
*/
|
|
|
|
|
public function getDiv( $value ) {
|
|
|
|
|
$msg = $this->formatMsg();
|
|
|
|
|
return '<div class="mw-editTools">' . $msg->parseAsBlock() . '</div>';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @since 1.20
|
|
|
|
|
*/
|
|
|
|
|
public function getRaw( $value ) {
|
|
|
|
|
return $this->getDiv( $value );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function formatMsg() {
|
2011-01-27 20:58:37 +00:00
|
|
|
if ( empty( $this->mParams['message'] ) ) {
|
2012-08-23 07:11:21 +00:00
|
|
|
$msg = $this->msg( 'edittools' );
|
2011-01-27 20:58:37 +00:00
|
|
|
} else {
|
2012-08-23 07:11:21 +00:00
|
|
|
$msg = $this->msg( $this->mParams['message'] );
|
2011-01-27 20:58:37 +00:00
|
|
|
if ( $msg->isDisabled() ) {
|
2012-08-23 07:11:21 +00:00
|
|
|
$msg = $this->msg( 'edittools' );
|
2011-01-27 20:58:37 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$msg->inContentLanguage();
|
2012-05-04 22:09:33 +00:00
|
|
|
return $msg;
|
2009-10-18 19:29:35 +00:00
|
|
|
}
|
2009-11-16 16:21:11 +00:00
|
|
|
}
|
2012-12-07 07:22:10 +00:00
|
|
|
|
|
|
|
|
class HTMLApiField extends HTMLFormField {
|
|
|
|
|
public function getTableRow( $value ) {
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function getDiv( $value ) {
|
|
|
|
|
return $this->getTableRow( $value );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function getRaw( $value ) {
|
|
|
|
|
return $this->getTableRow( $value );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function getInputHTML( $value ) {
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-04-27 01:49:02 +00:00
|
|
|
|
|
|
|
|
interface HTMLNestedFilterable {
|
|
|
|
|
/**
|
|
|
|
|
* Support for seperating multi-option preferences into multiple preferences
|
|
|
|
|
* Due to lack of array support.
|
|
|
|
|
* @param $data array
|
|
|
|
|
*/
|
|
|
|
|
function filterDataForSubmit( $data );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class HTMLFormFieldRequiredOptionsException extends MWException {
|
|
|
|
|
static public function create( HTMLFormField $field, array $missing ) {
|
|
|
|
|
return new self( sprintf(
|
|
|
|
|
"Form type `%s` expected the following parameters to be set: %s",
|
|
|
|
|
get_class( $field ),
|
|
|
|
|
implode( ', ', $missing )
|
|
|
|
|
) );
|
|
|
|
|
}
|
|
|
|
|
}
|