MediaWiki  REL1_23
HTMLForm.php
Go to the documentation of this file.
00001 <?php
00002 
00100 class HTMLForm extends ContextSource {
00101     // A mapping of 'type' inputs onto standard HTMLFormField subclasses
00102     public static $typeMappings = array(
00103         'api' => 'HTMLApiField',
00104         'text' => 'HTMLTextField',
00105         'textarea' => 'HTMLTextAreaField',
00106         'select' => 'HTMLSelectField',
00107         'radio' => 'HTMLRadioField',
00108         'multiselect' => 'HTMLMultiSelectField',
00109         'check' => 'HTMLCheckField',
00110         'toggle' => 'HTMLCheckField',
00111         'int' => 'HTMLIntField',
00112         'float' => 'HTMLFloatField',
00113         'info' => 'HTMLInfoField',
00114         'selectorother' => 'HTMLSelectOrOtherField',
00115         'selectandother' => 'HTMLSelectAndOtherField',
00116         'submit' => 'HTMLSubmitField',
00117         'hidden' => 'HTMLHiddenField',
00118         'edittools' => 'HTMLEditTools',
00119         'checkmatrix' => 'HTMLCheckMatrix',
00120         // HTMLTextField will output the correct type="" attribute automagically.
00121         // There are about four zillion other HTML5 input types, like range, but
00122         // we don't use those at the moment, so no point in adding all of them.
00123         'email' => 'HTMLTextField',
00124         'password' => 'HTMLTextField',
00125         'url' => 'HTMLTextField',
00126     );
00127 
00128     public $mFieldData;
00129 
00130     protected $mMessagePrefix;
00131 
00133     protected $mFlatFields;
00134 
00135     protected $mFieldTree;
00136     protected $mShowReset = false;
00137     protected $mShowSubmit = true;
00138 
00139     protected $mSubmitCallback;
00140     protected $mValidationErrorMessage;
00141 
00142     protected $mPre = '';
00143     protected $mHeader = '';
00144     protected $mFooter = '';
00145     protected $mSectionHeaders = array();
00146     protected $mSectionFooters = array();
00147     protected $mPost = '';
00148     protected $mId;
00149     protected $mTableId = '';
00150 
00151     protected $mSubmitID;
00152     protected $mSubmitName;
00153     protected $mSubmitText;
00154     protected $mSubmitTooltip;
00155 
00156     protected $mTitle;
00157     protected $mMethod = 'post';
00158 
00164     protected $mAction = false;
00165 
00166     protected $mUseMultipart = false;
00167     protected $mHiddenFields = array();
00168     protected $mButtons = array();
00169 
00170     protected $mWrapperLegend = false;
00171 
00179     protected $mSubSectionBeforeFields = true;
00180 
00186     protected $displayFormat = 'table';
00187 
00192     protected $availableDisplayFormats = array(
00193         'table',
00194         'div',
00195         'raw',
00196         'vform',
00197     );
00198 
00207     public function __construct( $descriptor, /*IContextSource*/ $context = null,
00208         $messagePrefix = ''
00209     ) {
00210         if ( $context instanceof IContextSource ) {
00211             $this->setContext( $context );
00212             $this->mTitle = false; // We don't need them to set a title
00213             $this->mMessagePrefix = $messagePrefix;
00214         } elseif ( is_null( $context ) && $messagePrefix !== '' ) {
00215             $this->mMessagePrefix = $messagePrefix;
00216         } elseif ( is_string( $context ) && $messagePrefix === '' ) {
00217             // B/C since 1.18
00218             // it's actually $messagePrefix
00219             $this->mMessagePrefix = $context;
00220         }
00221 
00222         // Expand out into a tree.
00223         $loadedDescriptor = array();
00224         $this->mFlatFields = array();
00225 
00226         foreach ( $descriptor as $fieldname => $info ) {
00227             $section = isset( $info['section'] )
00228                 ? $info['section']
00229                 : '';
00230 
00231             if ( isset( $info['type'] ) && $info['type'] == 'file' ) {
00232                 $this->mUseMultipart = true;
00233             }
00234 
00235             $field = self::loadInputFromParameters( $fieldname, $info );
00236             // FIXME During field's construct, the parent form isn't available!
00237             // could add a 'parent' name-value to $info, could add a third parameter.
00238             $field->mParent = $this;
00239 
00240             // vform gets too much space if empty labels generate HTML.
00241             if ( $this->isVForm() ) {
00242                 $field->setShowEmptyLabel( false );
00243             }
00244 
00245             $setSection =& $loadedDescriptor;
00246             if ( $section ) {
00247                 $sectionParts = explode( '/', $section );
00248 
00249                 while ( count( $sectionParts ) ) {
00250                     $newName = array_shift( $sectionParts );
00251 
00252                     if ( !isset( $setSection[$newName] ) ) {
00253                         $setSection[$newName] = array();
00254                     }
00255 
00256                     $setSection =& $setSection[$newName];
00257                 }
00258             }
00259 
00260             $setSection[$fieldname] = $field;
00261             $this->mFlatFields[$fieldname] = $field;
00262         }
00263 
00264         $this->mFieldTree = $loadedDescriptor;
00265     }
00266 
00277     public function setDisplayFormat( $format ) {
00278         if ( !in_array( $format, $this->availableDisplayFormats ) ) {
00279             throw new MWException( 'Display format must be one of ' .
00280                 print_r( $this->availableDisplayFormats, true ) );
00281         }
00282         $this->displayFormat = $format;
00283 
00284         return $this;
00285     }
00286 
00292     public function getDisplayFormat() {
00293         return $this->displayFormat;
00294     }
00295 
00301     public function isVForm() {
00302         return $this->displayFormat === 'vform';
00303     }
00304 
00310     static function addJS() {
00311         wfDeprecated( __METHOD__, '1.18' );
00312     }
00313 
00330     public static function getClassFromDescriptor( $fieldname, &$descriptor ) {
00331         if ( isset( $descriptor['class'] ) ) {
00332             $class = $descriptor['class'];
00333         } elseif ( isset( $descriptor['type'] ) ) {
00334             $class = self::$typeMappings[$descriptor['type']];
00335             $descriptor['class'] = $class;
00336         } else {
00337             $class = null;
00338         }
00339 
00340         if ( !$class ) {
00341             throw new MWException( "Descriptor with no class for $fieldname: " . print_r( $descriptor, true ) );
00342         }
00343         return $class;
00344     }
00345 
00355     public static function loadInputFromParameters( $fieldname, $descriptor ) {
00356         $class = self::getClassFromDescriptor( $fieldname, $descriptor );
00357 
00358         $descriptor['fieldname'] = $fieldname;
00359 
00360         # @todo This will throw a fatal error whenever someone try to use
00361         # 'class' to feed a CSS class instead of 'cssclass'. Would be
00362         # great to avoid the fatal error and show a nice error.
00363         $obj = new $class( $descriptor );
00364 
00365         return $obj;
00366     }
00367 
00377     function prepareForm() {
00378         # Check if we have the info we need
00379         if ( !$this->mTitle instanceof Title && $this->mTitle !== false ) {
00380             throw new MWException( "You must call setTitle() on an HTMLForm" );
00381         }
00382 
00383         # Load data from the request.
00384         $this->loadData();
00385 
00386         return $this;
00387     }
00388 
00393     function tryAuthorizedSubmit() {
00394         $result = false;
00395 
00396         $submit = false;
00397         if ( $this->getMethod() != 'post' ) {
00398             $submit = true; // no session check needed
00399         } elseif ( $this->getRequest()->wasPosted() ) {
00400             $editToken = $this->getRequest()->getVal( 'wpEditToken' );
00401             if ( $this->getUser()->isLoggedIn() || $editToken != null ) {
00402                 // Session tokens for logged-out users have no security value.
00403                 // However, if the user gave one, check it in order to give a nice
00404                 // "session expired" error instead of "permission denied" or such.
00405                 $submit = $this->getUser()->matchEditToken( $editToken );
00406             } else {
00407                 $submit = true;
00408             }
00409         }
00410 
00411         if ( $submit ) {
00412             $result = $this->trySubmit();
00413         }
00414 
00415         return $result;
00416     }
00417 
00424     function show() {
00425         $this->prepareForm();
00426 
00427         $result = $this->tryAuthorizedSubmit();
00428         if ( $result === true || ( $result instanceof Status && $result->isGood() ) ) {
00429             return $result;
00430         }
00431 
00432         $this->displayForm( $result );
00433 
00434         return false;
00435     }
00436 
00445     function trySubmit() {
00446         # Check for validation
00447         foreach ( $this->mFlatFields as $fieldname => $field ) {
00448             if ( !empty( $field->mParams['nodata'] ) ) {
00449                 continue;
00450             }
00451             if ( $field->validate(
00452                     $this->mFieldData[$fieldname],
00453                     $this->mFieldData )
00454                 !== true
00455             ) {
00456                 return isset( $this->mValidationErrorMessage )
00457                     ? $this->mValidationErrorMessage
00458                     : array( 'htmlform-invalid-input' );
00459             }
00460         }
00461 
00462         $callback = $this->mSubmitCallback;
00463         if ( !is_callable( $callback ) ) {
00464             throw new MWException( 'HTMLForm: no submit callback provided. Use ' .
00465                 'setSubmitCallback() to set one.' );
00466         }
00467 
00468         $data = $this->filterDataForSubmit( $this->mFieldData );
00469 
00470         $res = call_user_func( $callback, $data, $this );
00471 
00472         return $res;
00473     }
00474 
00486     function setSubmitCallback( $cb ) {
00487         $this->mSubmitCallback = $cb;
00488 
00489         return $this;
00490     }
00491 
00500     function setValidationErrorMessage( $msg ) {
00501         $this->mValidationErrorMessage = $msg;
00502 
00503         return $this;
00504     }
00505 
00513     function setIntro( $msg ) {
00514         $this->setPreText( $msg );
00515 
00516         return $this;
00517     }
00518 
00527     function setPreText( $msg ) {
00528         $this->mPre = $msg;
00529 
00530         return $this;
00531     }
00532 
00540     function addPreText( $msg ) {
00541         $this->mPre .= $msg;
00542 
00543         return $this;
00544     }
00545 
00554     function addHeaderText( $msg, $section = null ) {
00555         if ( is_null( $section ) ) {
00556             $this->mHeader .= $msg;
00557         } else {
00558             if ( !isset( $this->mSectionHeaders[$section] ) ) {
00559                 $this->mSectionHeaders[$section] = '';
00560             }
00561             $this->mSectionHeaders[$section] .= $msg;
00562         }
00563 
00564         return $this;
00565     }
00566 
00576     function setHeaderText( $msg, $section = null ) {
00577         if ( is_null( $section ) ) {
00578             $this->mHeader = $msg;
00579         } else {
00580             $this->mSectionHeaders[$section] = $msg;
00581         }
00582 
00583         return $this;
00584     }
00585 
00594     function addFooterText( $msg, $section = null ) {
00595         if ( is_null( $section ) ) {
00596             $this->mFooter .= $msg;
00597         } else {
00598             if ( !isset( $this->mSectionFooters[$section] ) ) {
00599                 $this->mSectionFooters[$section] = '';
00600             }
00601             $this->mSectionFooters[$section] .= $msg;
00602         }
00603 
00604         return $this;
00605     }
00606 
00616     function setFooterText( $msg, $section = null ) {
00617         if ( is_null( $section ) ) {
00618             $this->mFooter = $msg;
00619         } else {
00620             $this->mSectionFooters[$section] = $msg;
00621         }
00622 
00623         return $this;
00624     }
00625 
00633     function addPostText( $msg ) {
00634         $this->mPost .= $msg;
00635 
00636         return $this;
00637     }
00638 
00646     function setPostText( $msg ) {
00647         $this->mPost = $msg;
00648 
00649         return $this;
00650     }
00651 
00661     public function addHiddenField( $name, $value, $attribs = array() ) {
00662         $attribs += array( 'name' => $name );
00663         $this->mHiddenFields[] = array( $value, $attribs );
00664 
00665         return $this;
00666     }
00667 
00678     public function addHiddenFields( array $fields ) {
00679         foreach ( $fields as $name => $value ) {
00680             $this->mHiddenFields[] = array( $value, array( 'name' => $name ) );
00681         }
00682 
00683         return $this;
00684     }
00685 
00696     public function addButton( $name, $value, $id = null, $attribs = null ) {
00697         $this->mButtons[] = compact( 'name', 'value', 'id', 'attribs' );
00698 
00699         return $this;
00700     }
00701 
00714     function displayForm( $submitResult ) {
00715         $this->getOutput()->addHTML( $this->getHTML( $submitResult ) );
00716     }
00717 
00725     function getHTML( $submitResult ) {
00726         # For good measure (it is the default)
00727         $this->getOutput()->preventClickjacking();
00728         $this->getOutput()->addModules( 'mediawiki.htmlform' );
00729         if ( $this->isVForm() ) {
00730             $this->getOutput()->addModuleStyles( array(
00731                 'mediawiki.ui',
00732                 'mediawiki.ui.button',
00733             ) );
00734             // @todo Should vertical form set setWrapperLegend( false )
00735             // to hide ugly fieldsets?
00736         }
00737 
00738         $html = ''
00739             . $this->getErrors( $submitResult )
00740             . $this->mHeader
00741             . $this->getBody()
00742             . $this->getHiddenFields()
00743             . $this->getButtons()
00744             . $this->mFooter;
00745 
00746         $html = $this->wrapForm( $html );
00747 
00748         return '' . $this->mPre . $html . $this->mPost;
00749     }
00750 
00758     function wrapForm( $html ) {
00759 
00760         # Include a <fieldset> wrapper for style, if requested.
00761         if ( $this->mWrapperLegend !== false ) {
00762             $html = Xml::fieldset( $this->mWrapperLegend, $html );
00763         }
00764         # Use multipart/form-data
00765         $encType = $this->mUseMultipart
00766             ? 'multipart/form-data'
00767             : 'application/x-www-form-urlencoded';
00768         # Attributes
00769         $attribs = array(
00770             'action' => $this->getAction(),
00771             'method' => $this->getMethod(),
00772             'class' => array( 'visualClear' ),
00773             'enctype' => $encType,
00774         );
00775         if ( !empty( $this->mId ) ) {
00776             $attribs['id'] = $this->mId;
00777         }
00778 
00779         if ( $this->isVForm() ) {
00780             array_push( $attribs['class'], 'mw-ui-vform', 'mw-ui-container' );
00781         }
00782 
00783         return Html::rawElement( 'form', $attribs, $html );
00784     }
00785 
00790     function getHiddenFields() {
00791         global $wgArticlePath;
00792 
00793         $html = '';
00794         if ( $this->getMethod() == 'post' ) {
00795             $html .= Html::hidden(
00796                 'wpEditToken',
00797                 $this->getUser()->getEditToken(),
00798                 array( 'id' => 'wpEditToken' )
00799             ) . "\n";
00800             $html .= Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) . "\n";
00801         }
00802 
00803         if ( strpos( $wgArticlePath, '?' ) !== false && $this->getMethod() == 'get' ) {
00804             $html .= Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) . "\n";
00805         }
00806 
00807         foreach ( $this->mHiddenFields as $data ) {
00808             list( $value, $attribs ) = $data;
00809             $html .= Html::hidden( $attribs['name'], $value, $attribs ) . "\n";
00810         }
00811 
00812         return $html;
00813     }
00814 
00819     function getButtons() {
00820         $buttons = '';
00821 
00822         if ( $this->mShowSubmit ) {
00823             $attribs = array();
00824 
00825             if ( isset( $this->mSubmitID ) ) {
00826                 $attribs['id'] = $this->mSubmitID;
00827             }
00828 
00829             if ( isset( $this->mSubmitName ) ) {
00830                 $attribs['name'] = $this->mSubmitName;
00831             }
00832 
00833             if ( isset( $this->mSubmitTooltip ) ) {
00834                 $attribs += Linker::tooltipAndAccesskeyAttribs( $this->mSubmitTooltip );
00835             }
00836 
00837             $attribs['class'] = array( 'mw-htmlform-submit' );
00838 
00839             if ( $this->isVForm() ) {
00840                 // mw-ui-block is necessary because the buttons aren't necessarily in an
00841                 // immediate child div of the vform.
00842                 // @todo Let client specify if the primary submit button is progressive or destructive
00843                 array_push(
00844                     $attribs['class'],
00845                     'mw-ui-button',
00846                     'mw-ui-big',
00847                     'mw-ui-constructive',
00848                     'mw-ui-block'
00849                 );
00850             }
00851 
00852             $buttons .= Xml::submitButton( $this->getSubmitText(), $attribs ) . "\n";
00853         }
00854 
00855         if ( $this->mShowReset ) {
00856             $buttons .= Html::element(
00857                 'input',
00858                 array(
00859                     'type' => 'reset',
00860                     'value' => $this->msg( 'htmlform-reset' )->text()
00861                 )
00862             ) . "\n";
00863         }
00864 
00865         foreach ( $this->mButtons as $button ) {
00866             $attrs = array(
00867                 'type' => 'submit',
00868                 'name' => $button['name'],
00869                 'value' => $button['value']
00870             );
00871 
00872             if ( $button['attribs'] ) {
00873                 $attrs += $button['attribs'];
00874             }
00875 
00876             if ( isset( $button['id'] ) ) {
00877                 $attrs['id'] = $button['id'];
00878             }
00879 
00880             $buttons .= Html::element( 'input', $attrs ) . "\n";
00881         }
00882 
00883         $html = Html::rawElement( 'span',
00884             array( 'class' => 'mw-htmlform-submit-buttons' ), "\n$buttons" ) . "\n";
00885 
00886         // Buttons are top-level form elements in table and div layouts,
00887         // but vform wants all elements inside divs to get spaced-out block
00888         // styling.
00889         if ( $this->mShowSubmit && $this->isVForm() ) {
00890             $html = Html::rawElement( 'div', null, "\n$html" ) . "\n";
00891         }
00892 
00893         return $html;
00894     }
00895 
00900     function getBody() {
00901         return $this->displaySection( $this->mFieldTree, $this->mTableId );
00902     }
00903 
00911     function getErrors( $errors ) {
00912         if ( $errors instanceof Status ) {
00913             if ( $errors->isOK() ) {
00914                 $errorstr = '';
00915             } else {
00916                 $errorstr = $this->getOutput()->parse( $errors->getWikiText() );
00917             }
00918         } elseif ( is_array( $errors ) ) {
00919             $errorstr = $this->formatErrors( $errors );
00920         } else {
00921             $errorstr = $errors;
00922         }
00923 
00924         return $errorstr
00925             ? Html::rawElement( 'div', array( 'class' => 'error' ), $errorstr )
00926             : '';
00927     }
00928 
00936     public static function formatErrors( $errors ) {
00937         $errorstr = '';
00938 
00939         foreach ( $errors as $error ) {
00940             if ( is_array( $error ) ) {
00941                 $msg = array_shift( $error );
00942             } else {
00943                 $msg = $error;
00944                 $error = array();
00945             }
00946 
00947             $errorstr .= Html::rawElement(
00948                 'li',
00949                 array(),
00950                 wfMessage( $msg, $error )->parse()
00951             );
00952         }
00953 
00954         $errorstr = Html::rawElement( 'ul', array(), $errorstr );
00955 
00956         return $errorstr;
00957     }
00958 
00966     function setSubmitText( $t ) {
00967         $this->mSubmitText = $t;
00968 
00969         return $this;
00970     }
00971 
00980     public function setSubmitTextMsg( $msg ) {
00981         $this->setSubmitText( $this->msg( $msg )->text() );
00982 
00983         return $this;
00984     }
00985 
00990     function getSubmitText() {
00991         return $this->mSubmitText
00992             ? $this->mSubmitText
00993             : $this->msg( 'htmlform-submit' )->text();
00994     }
00995 
01001     public function setSubmitName( $name ) {
01002         $this->mSubmitName = $name;
01003 
01004         return $this;
01005     }
01006 
01012     public function setSubmitTooltip( $name ) {
01013         $this->mSubmitTooltip = $name;
01014 
01015         return $this;
01016     }
01017 
01026     function setSubmitID( $t ) {
01027         $this->mSubmitID = $t;
01028 
01029         return $this;
01030     }
01031 
01042     function suppressDefaultSubmit( $suppressSubmit = true ) {
01043         $this->mShowSubmit = !$suppressSubmit;
01044 
01045         return $this;
01046     }
01047 
01057     public function setTableId( $id ) {
01058         $this->mTableId = $id;
01059 
01060         return $this;
01061     }
01062 
01068     public function setId( $id ) {
01069         $this->mId = $id;
01070 
01071         return $this;
01072     }
01073 
01084     public function setWrapperLegend( $legend ) {
01085         $this->mWrapperLegend = $legend;
01086 
01087         return $this;
01088     }
01089 
01099     public function setWrapperLegendMsg( $msg ) {
01100         $this->setWrapperLegend( $this->msg( $msg )->text() );
01101 
01102         return $this;
01103     }
01104 
01114     function setMessagePrefix( $p ) {
01115         $this->mMessagePrefix = $p;
01116 
01117         return $this;
01118     }
01119 
01127     function setTitle( $t ) {
01128         $this->mTitle = $t;
01129 
01130         return $this;
01131     }
01132 
01137     function getTitle() {
01138         return $this->mTitle === false
01139             ? $this->getContext()->getTitle()
01140             : $this->mTitle;
01141     }
01142 
01150     public function setMethod( $method = 'post' ) {
01151         $this->mMethod = $method;
01152 
01153         return $this;
01154     }
01155 
01156     public function getMethod() {
01157         return $this->mMethod;
01158     }
01159 
01173     public function displaySection( $fields,
01174         $sectionName = '',
01175         $fieldsetIDPrefix = '',
01176         &$hasUserVisibleFields = false ) {
01177         $displayFormat = $this->getDisplayFormat();
01178 
01179         $html = '';
01180         $subsectionHtml = '';
01181         $hasLabel = false;
01182 
01183         switch ( $displayFormat ) {
01184             case 'table':
01185                 $getFieldHtmlMethod = 'getTableRow';
01186                 break;
01187             case 'vform':
01188                 // Close enough to a div.
01189                 $getFieldHtmlMethod = 'getDiv';
01190                 break;
01191             default:
01192                 $getFieldHtmlMethod = 'get' . ucfirst( $displayFormat );
01193         }
01194 
01195         foreach ( $fields as $key => $value ) {
01196             if ( $value instanceof HTMLFormField ) {
01197                 $v = empty( $value->mParams['nodata'] )
01198                     ? $this->mFieldData[$key]
01199                     : $value->getDefault();
01200                 $html .= $value->$getFieldHtmlMethod( $v );
01201 
01202                 $labelValue = trim( $value->getLabel() );
01203                 if ( $labelValue != '&#160;' && $labelValue !== '' ) {
01204                     $hasLabel = true;
01205                 }
01206 
01207                 if ( get_class( $value ) !== 'HTMLHiddenField' &&
01208                     get_class( $value ) !== 'HTMLApiField'
01209                 ) {
01210                     $hasUserVisibleFields = true;
01211                 }
01212             } elseif ( is_array( $value ) ) {
01213                 $subsectionHasVisibleFields = false;
01214                 $section =
01215                     $this->displaySection( $value,
01216                         "mw-htmlform-$key",
01217                         "$fieldsetIDPrefix$key-",
01218                         $subsectionHasVisibleFields );
01219                 $legend = null;
01220 
01221                 if ( $subsectionHasVisibleFields === true ) {
01222                     // Display the section with various niceties.
01223                     $hasUserVisibleFields = true;
01224 
01225                     $legend = $this->getLegend( $key );
01226 
01227                     if ( isset( $this->mSectionHeaders[$key] ) ) {
01228                         $section = $this->mSectionHeaders[$key] . $section;
01229                     }
01230                     if ( isset( $this->mSectionFooters[$key] ) ) {
01231                         $section .= $this->mSectionFooters[$key];
01232                     }
01233 
01234                     $attributes = array();
01235                     if ( $fieldsetIDPrefix ) {
01236                         $attributes['id'] = Sanitizer::escapeId( "$fieldsetIDPrefix$key" );
01237                     }
01238                     $subsectionHtml .= Xml::fieldset( $legend, $section, $attributes ) . "\n";
01239                 } else {
01240                     // Just return the inputs, nothing fancy.
01241                     $subsectionHtml .= $section;
01242                 }
01243             }
01244         }
01245 
01246         if ( $displayFormat !== 'raw' ) {
01247             $classes = array();
01248 
01249             if ( !$hasLabel ) { // Avoid strange spacing when no labels exist
01250                 $classes[] = 'mw-htmlform-nolabel';
01251             }
01252 
01253             $attribs = array(
01254                 'class' => implode( ' ', $classes ),
01255             );
01256 
01257             if ( $sectionName ) {
01258                 $attribs['id'] = Sanitizer::escapeId( $sectionName );
01259             }
01260 
01261             if ( $displayFormat === 'table' ) {
01262                 $html = Html::rawElement( 'table',
01263                         $attribs,
01264                         Html::rawElement( 'tbody', array(), "\n$html\n" ) ) . "\n";
01265             } elseif ( $displayFormat === 'div' || $displayFormat === 'vform' ) {
01266                 $html = Html::rawElement( 'div', $attribs, "\n$html\n" );
01267             }
01268         }
01269 
01270         if ( $this->mSubSectionBeforeFields ) {
01271             return $subsectionHtml . "\n" . $html;
01272         } else {
01273             return $html . "\n" . $subsectionHtml;
01274         }
01275     }
01276 
01280     function loadData() {
01281         $fieldData = array();
01282 
01283         foreach ( $this->mFlatFields as $fieldname => $field ) {
01284             if ( !empty( $field->mParams['nodata'] ) ) {
01285                 continue;
01286             } elseif ( !empty( $field->mParams['disabled'] ) ) {
01287                 $fieldData[$fieldname] = $field->getDefault();
01288             } else {
01289                 $fieldData[$fieldname] = $field->loadDataFromRequest( $this->getRequest() );
01290             }
01291         }
01292 
01293         # Filter data.
01294         foreach ( $fieldData as $name => &$value ) {
01295             $field = $this->mFlatFields[$name];
01296             $value = $field->filter( $value, $this->mFlatFields );
01297         }
01298 
01299         $this->mFieldData = $fieldData;
01300     }
01301 
01310     function suppressReset( $suppressReset = true ) {
01311         $this->mShowReset = !$suppressReset;
01312 
01313         return $this;
01314     }
01315 
01325     function filterDataForSubmit( $data ) {
01326         return $data;
01327     }
01328 
01337     public function getLegend( $key ) {
01338         return $this->msg( "{$this->mMessagePrefix}-$key" )->text();
01339     }
01340 
01351     public function setAction( $action ) {
01352         $this->mAction = $action;
01353 
01354         return $this;
01355     }
01356 
01364     public function getAction() {
01365         global $wgScript, $wgArticlePath;
01366 
01367         // If an action is alredy provided, return it
01368         if ( $this->mAction !== false ) {
01369             return $this->mAction;
01370         }
01371 
01372         // Check whether we are in GET mode and $wgArticlePath contains a "?"
01373         // meaning that getLocalURL() would return something like "index.php?title=...".
01374         // As browser remove the query string before submitting GET forms,
01375         // it means that the title would be lost. In such case use $wgScript instead
01376         // and put title in an hidden field (see getHiddenFields()).
01377         if ( strpos( $wgArticlePath, '?' ) !== false && $this->getMethod() === 'get' ) {
01378             return $wgScript;
01379         }
01380 
01381         return $this->getTitle()->getLocalURL();
01382     }
01383 }