MediaWiki
REL1_24
|
00001 <?php 00002 00101 class HTMLForm extends ContextSource { 00102 // A mapping of 'type' inputs onto standard HTMLFormField subclasses 00103 public static $typeMappings = array( 00104 'api' => 'HTMLApiField', 00105 'text' => 'HTMLTextField', 00106 'textarea' => 'HTMLTextAreaField', 00107 'select' => 'HTMLSelectField', 00108 'radio' => 'HTMLRadioField', 00109 'multiselect' => 'HTMLMultiSelectField', 00110 'limitselect' => 'HTMLSelectLimitField', 00111 'check' => 'HTMLCheckField', 00112 'toggle' => 'HTMLCheckField', 00113 'int' => 'HTMLIntField', 00114 'float' => 'HTMLFloatField', 00115 'info' => 'HTMLInfoField', 00116 'selectorother' => 'HTMLSelectOrOtherField', 00117 'selectandother' => 'HTMLSelectAndOtherField', 00118 'submit' => 'HTMLSubmitField', 00119 'hidden' => 'HTMLHiddenField', 00120 'edittools' => 'HTMLEditTools', 00121 'checkmatrix' => 'HTMLCheckMatrix', 00122 'cloner' => 'HTMLFormFieldCloner', 00123 'autocompleteselect' => 'HTMLAutoCompleteSelectField', 00124 // HTMLTextField will output the correct type="" attribute automagically. 00125 // There are about four zillion other HTML5 input types, like range, but 00126 // we don't use those at the moment, so no point in adding all of them. 00127 'email' => 'HTMLTextField', 00128 'password' => 'HTMLTextField', 00129 'url' => 'HTMLTextField', 00130 ); 00131 00132 public $mFieldData; 00133 00134 protected $mMessagePrefix; 00135 00137 protected $mFlatFields; 00138 00139 protected $mFieldTree; 00140 protected $mShowReset = false; 00141 protected $mShowSubmit = true; 00142 protected $mSubmitModifierClass = 'mw-ui-constructive'; 00143 00144 protected $mSubmitCallback; 00145 protected $mValidationErrorMessage; 00146 00147 protected $mPre = ''; 00148 protected $mHeader = ''; 00149 protected $mFooter = ''; 00150 protected $mSectionHeaders = array(); 00151 protected $mSectionFooters = array(); 00152 protected $mPost = ''; 00153 protected $mId; 00154 protected $mTableId = ''; 00155 00156 protected $mSubmitID; 00157 protected $mSubmitName; 00158 protected $mSubmitText; 00159 protected $mSubmitTooltip; 00160 00161 protected $mTitle; 00162 protected $mMethod = 'post'; 00163 protected $mWasSubmitted = false; 00164 00170 protected $mAction = false; 00171 00172 protected $mUseMultipart = false; 00173 protected $mHiddenFields = array(); 00174 protected $mButtons = array(); 00175 00176 protected $mWrapperLegend = false; 00177 00182 protected $mTokenSalt = ''; 00183 00191 protected $mSubSectionBeforeFields = true; 00192 00198 protected $displayFormat = 'table'; 00199 00204 protected $availableDisplayFormats = array( 00205 'table', 00206 'div', 00207 'raw', 00208 'vform', 00209 ); 00210 00219 public function __construct( $descriptor, /*IContextSource*/ $context = null, 00220 $messagePrefix = '' 00221 ) { 00222 if ( $context instanceof IContextSource ) { 00223 $this->setContext( $context ); 00224 $this->mTitle = false; // We don't need them to set a title 00225 $this->mMessagePrefix = $messagePrefix; 00226 } elseif ( is_null( $context ) && $messagePrefix !== '' ) { 00227 $this->mMessagePrefix = $messagePrefix; 00228 } elseif ( is_string( $context ) && $messagePrefix === '' ) { 00229 // B/C since 1.18 00230 // it's actually $messagePrefix 00231 $this->mMessagePrefix = $context; 00232 } 00233 00234 // Expand out into a tree. 00235 $loadedDescriptor = array(); 00236 $this->mFlatFields = array(); 00237 00238 foreach ( $descriptor as $fieldname => $info ) { 00239 $section = isset( $info['section'] ) 00240 ? $info['section'] 00241 : ''; 00242 00243 if ( isset( $info['type'] ) && $info['type'] == 'file' ) { 00244 $this->mUseMultipart = true; 00245 } 00246 00247 $field = self::loadInputFromParameters( $fieldname, $info ); 00248 // FIXME During field's construct, the parent form isn't available! 00249 // could add a 'parent' name-value to $info, could add a third parameter. 00250 $field->mParent = $this; 00251 00252 // vform gets too much space if empty labels generate HTML. 00253 if ( $this->isVForm() ) { 00254 $field->setShowEmptyLabel( false ); 00255 } 00256 00257 $setSection =& $loadedDescriptor; 00258 if ( $section ) { 00259 $sectionParts = explode( '/', $section ); 00260 00261 while ( count( $sectionParts ) ) { 00262 $newName = array_shift( $sectionParts ); 00263 00264 if ( !isset( $setSection[$newName] ) ) { 00265 $setSection[$newName] = array(); 00266 } 00267 00268 $setSection =& $setSection[$newName]; 00269 } 00270 } 00271 00272 $setSection[$fieldname] = $field; 00273 $this->mFlatFields[$fieldname] = $field; 00274 } 00275 00276 $this->mFieldTree = $loadedDescriptor; 00277 } 00278 00289 public function setDisplayFormat( $format ) { 00290 if ( !in_array( $format, $this->availableDisplayFormats ) ) { 00291 throw new MWException( 'Display format must be one of ' . 00292 print_r( $this->availableDisplayFormats, true ) ); 00293 } 00294 $this->displayFormat = $format; 00295 00296 return $this; 00297 } 00298 00304 public function getDisplayFormat() { 00305 $format = $this->displayFormat; 00306 if ( !$this->getConfig()->get( 'HTMLFormAllowTableFormat' ) && $format === 'table' ) { 00307 $format = 'div'; 00308 } 00309 return $format; 00310 } 00311 00317 public function isVForm() { 00318 return $this->displayFormat === 'vform'; 00319 } 00320 00337 public static function getClassFromDescriptor( $fieldname, &$descriptor ) { 00338 if ( isset( $descriptor['class'] ) ) { 00339 $class = $descriptor['class']; 00340 } elseif ( isset( $descriptor['type'] ) ) { 00341 $class = self::$typeMappings[$descriptor['type']]; 00342 $descriptor['class'] = $class; 00343 } else { 00344 $class = null; 00345 } 00346 00347 if ( !$class ) { 00348 throw new MWException( "Descriptor with no class for $fieldname: " 00349 . print_r( $descriptor, true ) ); 00350 } 00351 00352 return $class; 00353 } 00354 00364 public static function loadInputFromParameters( $fieldname, $descriptor ) { 00365 $class = self::getClassFromDescriptor( $fieldname, $descriptor ); 00366 00367 $descriptor['fieldname'] = $fieldname; 00368 00369 # @todo This will throw a fatal error whenever someone try to use 00370 # 'class' to feed a CSS class instead of 'cssclass'. Would be 00371 # great to avoid the fatal error and show a nice error. 00372 $obj = new $class( $descriptor ); 00373 00374 return $obj; 00375 } 00376 00386 function prepareForm() { 00387 # Check if we have the info we need 00388 if ( !$this->mTitle instanceof Title && $this->mTitle !== false ) { 00389 throw new MWException( "You must call setTitle() on an HTMLForm" ); 00390 } 00391 00392 # Load data from the request. 00393 $this->loadData(); 00394 00395 return $this; 00396 } 00397 00402 function tryAuthorizedSubmit() { 00403 $result = false; 00404 00405 $submit = false; 00406 if ( $this->getMethod() != 'post' ) { 00407 $submit = true; // no session check needed 00408 } elseif ( $this->getRequest()->wasPosted() ) { 00409 $editToken = $this->getRequest()->getVal( 'wpEditToken' ); 00410 if ( $this->getUser()->isLoggedIn() || $editToken != null ) { 00411 // Session tokens for logged-out users have no security value. 00412 // However, if the user gave one, check it in order to give a nice 00413 // "session expired" error instead of "permission denied" or such. 00414 $submit = $this->getUser()->matchEditToken( $editToken, $this->mTokenSalt ); 00415 } else { 00416 $submit = true; 00417 } 00418 } 00419 00420 if ( $submit ) { 00421 $this->mWasSubmitted = true; 00422 $result = $this->trySubmit(); 00423 } 00424 00425 return $result; 00426 } 00427 00434 function show() { 00435 $this->prepareForm(); 00436 00437 $result = $this->tryAuthorizedSubmit(); 00438 if ( $result === true || ( $result instanceof Status && $result->isGood() ) ) { 00439 return $result; 00440 } 00441 00442 $this->displayForm( $result ); 00443 00444 return false; 00445 } 00446 00458 function trySubmit() { 00459 $this->mWasSubmitted = true; 00460 00461 # Check for cancelled submission 00462 foreach ( $this->mFlatFields as $fieldname => $field ) { 00463 if ( !empty( $field->mParams['nodata'] ) ) { 00464 continue; 00465 } 00466 if ( $field->cancelSubmit( $this->mFieldData[$fieldname], $this->mFieldData ) ) { 00467 $this->mWasSubmitted = false; 00468 return false; 00469 } 00470 } 00471 00472 # Check for validation 00473 foreach ( $this->mFlatFields as $fieldname => $field ) { 00474 if ( !empty( $field->mParams['nodata'] ) ) { 00475 continue; 00476 } 00477 if ( $field->isHidden( $this->mFieldData ) ) { 00478 continue; 00479 } 00480 if ( $field->validate( 00481 $this->mFieldData[$fieldname], 00482 $this->mFieldData ) 00483 !== true 00484 ) { 00485 return isset( $this->mValidationErrorMessage ) 00486 ? $this->mValidationErrorMessage 00487 : array( 'htmlform-invalid-input' ); 00488 } 00489 } 00490 00491 $callback = $this->mSubmitCallback; 00492 if ( !is_callable( $callback ) ) { 00493 throw new MWException( 'HTMLForm: no submit callback provided. Use ' . 00494 'setSubmitCallback() to set one.' ); 00495 } 00496 00497 $data = $this->filterDataForSubmit( $this->mFieldData ); 00498 00499 $res = call_user_func( $callback, $data, $this ); 00500 if ( $res === false ) { 00501 $this->mWasSubmitted = false; 00502 } 00503 00504 return $res; 00505 } 00506 00518 function wasSubmitted() { 00519 return $this->mWasSubmitted; 00520 } 00521 00532 function setSubmitCallback( $cb ) { 00533 $this->mSubmitCallback = $cb; 00534 00535 return $this; 00536 } 00537 00546 function setValidationErrorMessage( $msg ) { 00547 $this->mValidationErrorMessage = $msg; 00548 00549 return $this; 00550 } 00551 00559 function setIntro( $msg ) { 00560 $this->setPreText( $msg ); 00561 00562 return $this; 00563 } 00564 00573 function setPreText( $msg ) { 00574 $this->mPre = $msg; 00575 00576 return $this; 00577 } 00578 00586 function addPreText( $msg ) { 00587 $this->mPre .= $msg; 00588 00589 return $this; 00590 } 00591 00600 function addHeaderText( $msg, $section = null ) { 00601 if ( is_null( $section ) ) { 00602 $this->mHeader .= $msg; 00603 } else { 00604 if ( !isset( $this->mSectionHeaders[$section] ) ) { 00605 $this->mSectionHeaders[$section] = ''; 00606 } 00607 $this->mSectionHeaders[$section] .= $msg; 00608 } 00609 00610 return $this; 00611 } 00612 00622 function setHeaderText( $msg, $section = null ) { 00623 if ( is_null( $section ) ) { 00624 $this->mHeader = $msg; 00625 } else { 00626 $this->mSectionHeaders[$section] = $msg; 00627 } 00628 00629 return $this; 00630 } 00631 00640 function addFooterText( $msg, $section = null ) { 00641 if ( is_null( $section ) ) { 00642 $this->mFooter .= $msg; 00643 } else { 00644 if ( !isset( $this->mSectionFooters[$section] ) ) { 00645 $this->mSectionFooters[$section] = ''; 00646 } 00647 $this->mSectionFooters[$section] .= $msg; 00648 } 00649 00650 return $this; 00651 } 00652 00662 function setFooterText( $msg, $section = null ) { 00663 if ( is_null( $section ) ) { 00664 $this->mFooter = $msg; 00665 } else { 00666 $this->mSectionFooters[$section] = $msg; 00667 } 00668 00669 return $this; 00670 } 00671 00679 function addPostText( $msg ) { 00680 $this->mPost .= $msg; 00681 00682 return $this; 00683 } 00684 00692 function setPostText( $msg ) { 00693 $this->mPost = $msg; 00694 00695 return $this; 00696 } 00697 00707 public function addHiddenField( $name, $value, $attribs = array() ) { 00708 $attribs += array( 'name' => $name ); 00709 $this->mHiddenFields[] = array( $value, $attribs ); 00710 00711 return $this; 00712 } 00713 00724 public function addHiddenFields( array $fields ) { 00725 foreach ( $fields as $name => $value ) { 00726 $this->mHiddenFields[] = array( $value, array( 'name' => $name ) ); 00727 } 00728 00729 return $this; 00730 } 00731 00742 public function addButton( $name, $value, $id = null, $attribs = null ) { 00743 $this->mButtons[] = compact( 'name', 'value', 'id', 'attribs' ); 00744 00745 return $this; 00746 } 00747 00757 public function setTokenSalt( $salt ) { 00758 $this->mTokenSalt = $salt; 00759 00760 return $this; 00761 } 00762 00775 function displayForm( $submitResult ) { 00776 $this->getOutput()->addHTML( $this->getHTML( $submitResult ) ); 00777 } 00778 00786 function getHTML( $submitResult ) { 00787 # For good measure (it is the default) 00788 $this->getOutput()->preventClickjacking(); 00789 $this->getOutput()->addModules( 'mediawiki.htmlform' ); 00790 if ( $this->isVForm() ) { 00791 $this->getOutput()->addModuleStyles( array( 00792 'mediawiki.ui', 00793 'mediawiki.ui.button', 00794 ) ); 00795 // @todo Should vertical form set setWrapperLegend( false ) 00796 // to hide ugly fieldsets? 00797 } 00798 00799 $html = '' 00800 . $this->getErrors( $submitResult ) 00801 . $this->mHeader 00802 . $this->getBody() 00803 . $this->getHiddenFields() 00804 . $this->getButtons() 00805 . $this->mFooter; 00806 00807 $html = $this->wrapForm( $html ); 00808 00809 return '' . $this->mPre . $html . $this->mPost; 00810 } 00811 00819 function wrapForm( $html ) { 00820 00821 # Include a <fieldset> wrapper for style, if requested. 00822 if ( $this->mWrapperLegend !== false ) { 00823 $html = Xml::fieldset( $this->mWrapperLegend, $html ); 00824 } 00825 # Use multipart/form-data 00826 $encType = $this->mUseMultipart 00827 ? 'multipart/form-data' 00828 : 'application/x-www-form-urlencoded'; 00829 # Attributes 00830 $attribs = array( 00831 'action' => $this->getAction(), 00832 'method' => $this->getMethod(), 00833 'class' => array( 'visualClear' ), 00834 'enctype' => $encType, 00835 ); 00836 if ( !empty( $this->mId ) ) { 00837 $attribs['id'] = $this->mId; 00838 } 00839 00840 if ( $this->isVForm() ) { 00841 array_push( $attribs['class'], 'mw-ui-vform', 'mw-ui-container' ); 00842 } 00843 00844 return Html::rawElement( 'form', $attribs, $html ); 00845 } 00846 00851 function getHiddenFields() { 00852 $html = ''; 00853 if ( $this->getMethod() == 'post' ) { 00854 $html .= Html::hidden( 00855 'wpEditToken', 00856 $this->getUser()->getEditToken( $this->mTokenSalt ), 00857 array( 'id' => 'wpEditToken' ) 00858 ) . "\n"; 00859 $html .= Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) . "\n"; 00860 } 00861 00862 $articlePath = $this->getConfig()->get( 'ArticlePath' ); 00863 if ( strpos( $articlePath, '?' ) !== false && $this->getMethod() == 'get' ) { 00864 $html .= Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) . "\n"; 00865 } 00866 00867 foreach ( $this->mHiddenFields as $data ) { 00868 list( $value, $attribs ) = $data; 00869 $html .= Html::hidden( $attribs['name'], $value, $attribs ) . "\n"; 00870 } 00871 00872 return $html; 00873 } 00874 00879 function getButtons() { 00880 $buttons = ''; 00881 $useMediaWikiUIEverywhere = $this->getConfig()->get( 'UseMediaWikiUIEverywhere' ); 00882 00883 if ( $this->mShowSubmit ) { 00884 $attribs = array(); 00885 00886 if ( isset( $this->mSubmitID ) ) { 00887 $attribs['id'] = $this->mSubmitID; 00888 } 00889 00890 if ( isset( $this->mSubmitName ) ) { 00891 $attribs['name'] = $this->mSubmitName; 00892 } 00893 00894 if ( isset( $this->mSubmitTooltip ) ) { 00895 $attribs += Linker::tooltipAndAccesskeyAttribs( $this->mSubmitTooltip ); 00896 } 00897 00898 $attribs['class'] = array( 'mw-htmlform-submit' ); 00899 00900 if ( $this->isVForm() || $useMediaWikiUIEverywhere ) { 00901 array_push( $attribs['class'], 'mw-ui-button', $this->mSubmitModifierClass ); 00902 } 00903 00904 if ( $this->isVForm() ) { 00905 // mw-ui-block is necessary because the buttons aren't necessarily in an 00906 // immediate child div of the vform. 00907 // @todo Let client specify if the primary submit button is progressive or destructive 00908 array_push( 00909 $attribs['class'], 00910 'mw-ui-big', 00911 'mw-ui-block' 00912 ); 00913 } 00914 00915 $buttons .= Xml::submitButton( $this->getSubmitText(), $attribs ) . "\n"; 00916 } 00917 00918 if ( $this->mShowReset ) { 00919 $buttons .= Html::element( 00920 'input', 00921 array( 00922 'type' => 'reset', 00923 'value' => $this->msg( 'htmlform-reset' )->text() 00924 ) 00925 ) . "\n"; 00926 } 00927 00928 foreach ( $this->mButtons as $button ) { 00929 $attrs = array( 00930 'type' => 'submit', 00931 'name' => $button['name'], 00932 'value' => $button['value'] 00933 ); 00934 00935 if ( $button['attribs'] ) { 00936 $attrs += $button['attribs']; 00937 } 00938 00939 if ( isset( $button['id'] ) ) { 00940 $attrs['id'] = $button['id']; 00941 } 00942 00943 if ( $this->isVForm() || $useMediaWikiUIEverywhere ) { 00944 if ( isset( $attrs['class'] ) ) { 00945 $attrs['class'] .= ' mw-ui-button'; 00946 } else { 00947 $attrs['class'] = 'mw-ui-button'; 00948 } 00949 if ( $this->isVForm() ) { 00950 $attrs['class'] .= ' mw-ui-big mw-ui-block'; 00951 } 00952 } 00953 00954 $buttons .= Html::element( 'input', $attrs ) . "\n"; 00955 } 00956 00957 $html = Html::rawElement( 'span', 00958 array( 'class' => 'mw-htmlform-submit-buttons' ), "\n$buttons" ) . "\n"; 00959 00960 // Buttons are top-level form elements in table and div layouts, 00961 // but vform wants all elements inside divs to get spaced-out block 00962 // styling. 00963 if ( $this->mShowSubmit && $this->isVForm() ) { 00964 $html = Html::rawElement( 'div', null, "\n$html" ) . "\n"; 00965 } 00966 00967 return $html; 00968 } 00969 00974 function getBody() { 00975 return $this->displaySection( $this->mFieldTree, $this->mTableId ); 00976 } 00977 00985 function getErrors( $errors ) { 00986 if ( $errors instanceof Status ) { 00987 if ( $errors->isOK() ) { 00988 $errorstr = ''; 00989 } else { 00990 $errorstr = $this->getOutput()->parse( $errors->getWikiText() ); 00991 } 00992 } elseif ( is_array( $errors ) ) { 00993 $errorstr = $this->formatErrors( $errors ); 00994 } else { 00995 $errorstr = $errors; 00996 } 00997 00998 return $errorstr 00999 ? Html::rawElement( 'div', array( 'class' => 'error' ), $errorstr ) 01000 : ''; 01001 } 01002 01010 public static function formatErrors( $errors ) { 01011 $errorstr = ''; 01012 01013 foreach ( $errors as $error ) { 01014 if ( is_array( $error ) ) { 01015 $msg = array_shift( $error ); 01016 } else { 01017 $msg = $error; 01018 $error = array(); 01019 } 01020 01021 $errorstr .= Html::rawElement( 01022 'li', 01023 array(), 01024 wfMessage( $msg, $error )->parse() 01025 ); 01026 } 01027 01028 $errorstr = Html::rawElement( 'ul', array(), $errorstr ); 01029 01030 return $errorstr; 01031 } 01032 01040 function setSubmitText( $t ) { 01041 $this->mSubmitText = $t; 01042 01043 return $this; 01044 } 01045 01050 public function setSubmitDestructive() { 01051 $this->mSubmitModifierClass = 'mw-ui-destructive'; 01052 } 01053 01062 public function setSubmitTextMsg( $msg ) { 01063 if ( !$msg instanceof Message ) { 01064 $msg = $this->msg( $msg ); 01065 } 01066 $this->setSubmitText( $msg->text() ); 01067 01068 return $this; 01069 } 01070 01075 function getSubmitText() { 01076 return $this->mSubmitText 01077 ? $this->mSubmitText 01078 : $this->msg( 'htmlform-submit' )->text(); 01079 } 01080 01086 public function setSubmitName( $name ) { 01087 $this->mSubmitName = $name; 01088 01089 return $this; 01090 } 01091 01097 public function setSubmitTooltip( $name ) { 01098 $this->mSubmitTooltip = $name; 01099 01100 return $this; 01101 } 01102 01111 function setSubmitID( $t ) { 01112 $this->mSubmitID = $t; 01113 01114 return $this; 01115 } 01116 01127 function suppressDefaultSubmit( $suppressSubmit = true ) { 01128 $this->mShowSubmit = !$suppressSubmit; 01129 01130 return $this; 01131 } 01132 01142 public function setTableId( $id ) { 01143 $this->mTableId = $id; 01144 01145 return $this; 01146 } 01147 01153 public function setId( $id ) { 01154 $this->mId = $id; 01155 01156 return $this; 01157 } 01158 01169 public function setWrapperLegend( $legend ) { 01170 $this->mWrapperLegend = $legend; 01171 01172 return $this; 01173 } 01174 01184 public function setWrapperLegendMsg( $msg ) { 01185 if ( !$msg instanceof Message ) { 01186 $msg = $this->msg( $msg ); 01187 } 01188 $this->setWrapperLegend( $msg->text() ); 01189 01190 return $this; 01191 } 01192 01202 function setMessagePrefix( $p ) { 01203 $this->mMessagePrefix = $p; 01204 01205 return $this; 01206 } 01207 01215 function setTitle( $t ) { 01216 $this->mTitle = $t; 01217 01218 return $this; 01219 } 01220 01225 function getTitle() { 01226 return $this->mTitle === false 01227 ? $this->getContext()->getTitle() 01228 : $this->mTitle; 01229 } 01230 01238 public function setMethod( $method = 'post' ) { 01239 $this->mMethod = $method; 01240 01241 return $this; 01242 } 01243 01244 public function getMethod() { 01245 return $this->mMethod; 01246 } 01247 01261 public function displaySection( $fields, 01262 $sectionName = '', 01263 $fieldsetIDPrefix = '', 01264 &$hasUserVisibleFields = false ) { 01265 $displayFormat = $this->getDisplayFormat(); 01266 01267 $html = ''; 01268 $subsectionHtml = ''; 01269 $hasLabel = false; 01270 01271 switch ( $displayFormat ) { 01272 case 'table': 01273 $getFieldHtmlMethod = 'getTableRow'; 01274 break; 01275 case 'vform': 01276 // Close enough to a div. 01277 $getFieldHtmlMethod = 'getDiv'; 01278 break; 01279 case 'div': 01280 $getFieldHtmlMethod = 'getDiv'; 01281 break; 01282 default: 01283 $getFieldHtmlMethod = 'get' . ucfirst( $displayFormat ); 01284 } 01285 01286 foreach ( $fields as $key => $value ) { 01287 if ( $value instanceof HTMLFormField ) { 01288 $v = empty( $value->mParams['nodata'] ) 01289 ? $this->mFieldData[$key] 01290 : $value->getDefault(); 01291 $html .= $value->$getFieldHtmlMethod( $v ); 01292 01293 $labelValue = trim( $value->getLabel() ); 01294 if ( $labelValue != ' ' && $labelValue !== '' ) { 01295 $hasLabel = true; 01296 } 01297 01298 if ( get_class( $value ) !== 'HTMLHiddenField' && 01299 get_class( $value ) !== 'HTMLApiField' 01300 ) { 01301 $hasUserVisibleFields = true; 01302 } 01303 } elseif ( is_array( $value ) ) { 01304 $subsectionHasVisibleFields = false; 01305 $section = 01306 $this->displaySection( $value, 01307 "mw-htmlform-$key", 01308 "$fieldsetIDPrefix$key-", 01309 $subsectionHasVisibleFields ); 01310 $legend = null; 01311 01312 if ( $subsectionHasVisibleFields === true ) { 01313 // Display the section with various niceties. 01314 $hasUserVisibleFields = true; 01315 01316 $legend = $this->getLegend( $key ); 01317 01318 if ( isset( $this->mSectionHeaders[$key] ) ) { 01319 $section = $this->mSectionHeaders[$key] . $section; 01320 } 01321 if ( isset( $this->mSectionFooters[$key] ) ) { 01322 $section .= $this->mSectionFooters[$key]; 01323 } 01324 01325 $attributes = array(); 01326 if ( $fieldsetIDPrefix ) { 01327 $attributes['id'] = Sanitizer::escapeId( "$fieldsetIDPrefix$key" ); 01328 } 01329 $subsectionHtml .= Xml::fieldset( $legend, $section, $attributes ) . "\n"; 01330 } else { 01331 // Just return the inputs, nothing fancy. 01332 $subsectionHtml .= $section; 01333 } 01334 } 01335 } 01336 01337 if ( $displayFormat !== 'raw' ) { 01338 $classes = array(); 01339 01340 if ( !$hasLabel ) { // Avoid strange spacing when no labels exist 01341 $classes[] = 'mw-htmlform-nolabel'; 01342 } 01343 01344 $attribs = array( 01345 'class' => implode( ' ', $classes ), 01346 ); 01347 01348 if ( $sectionName ) { 01349 $attribs['id'] = Sanitizer::escapeId( $sectionName ); 01350 } 01351 01352 if ( $displayFormat === 'table' ) { 01353 $html = Html::rawElement( 'table', 01354 $attribs, 01355 Html::rawElement( 'tbody', array(), "\n$html\n" ) ) . "\n"; 01356 } elseif ( $displayFormat === 'div' || $displayFormat === 'vform' ) { 01357 $html = Html::rawElement( 'div', $attribs, "\n$html\n" ); 01358 } 01359 } 01360 01361 if ( $this->mSubSectionBeforeFields ) { 01362 return $subsectionHtml . "\n" . $html; 01363 } else { 01364 return $html . "\n" . $subsectionHtml; 01365 } 01366 } 01367 01371 function loadData() { 01372 $fieldData = array(); 01373 01374 foreach ( $this->mFlatFields as $fieldname => $field ) { 01375 if ( !empty( $field->mParams['nodata'] ) ) { 01376 continue; 01377 } elseif ( !empty( $field->mParams['disabled'] ) ) { 01378 $fieldData[$fieldname] = $field->getDefault(); 01379 } else { 01380 $fieldData[$fieldname] = $field->loadDataFromRequest( $this->getRequest() ); 01381 } 01382 } 01383 01384 # Filter data. 01385 foreach ( $fieldData as $name => &$value ) { 01386 $field = $this->mFlatFields[$name]; 01387 $value = $field->filter( $value, $this->mFlatFields ); 01388 } 01389 01390 $this->mFieldData = $fieldData; 01391 } 01392 01400 function suppressReset( $suppressReset = true ) { 01401 $this->mShowReset = !$suppressReset; 01402 01403 return $this; 01404 } 01405 01415 function filterDataForSubmit( $data ) { 01416 return $data; 01417 } 01418 01427 public function getLegend( $key ) { 01428 return $this->msg( "{$this->mMessagePrefix}-$key" )->text(); 01429 } 01430 01441 public function setAction( $action ) { 01442 $this->mAction = $action; 01443 01444 return $this; 01445 } 01446 01454 public function getAction() { 01455 // If an action is alredy provided, return it 01456 if ( $this->mAction !== false ) { 01457 return $this->mAction; 01458 } 01459 01460 $articlePath = $this->getConfig()->get( 'ArticlePath' ); 01461 // Check whether we are in GET mode and the ArticlePath contains a "?" 01462 // meaning that getLocalURL() would return something like "index.php?title=...". 01463 // As browser remove the query string before submitting GET forms, 01464 // it means that the title would be lost. In such case use wfScript() instead 01465 // and put title in an hidden field (see getHiddenFields()). 01466 if ( strpos( $articlePath, '?' ) !== false && $this->getMethod() === 'get' ) { 01467 return wfScript(); 01468 } 01469 01470 return $this->getTitle()->getLocalURL(); 01471 } 01472 }