MediaWiki
REL1_23
|
00001 <?php 00002 00007 abstract class HTMLFormField { 00008 public $mParams; 00009 00010 protected $mValidationCallback; 00011 protected $mFilterCallback; 00012 protected $mName; 00013 protected $mLabel; # String label. Set on construction 00014 protected $mID; 00015 protected $mClass = ''; 00016 protected $mDefault; 00017 protected $mOptions = false; 00018 protected $mOptionsLabelsNotFromMessage = false; 00019 00024 protected $mShowEmptyLabels = true; 00025 00029 public $mParent; 00030 00041 abstract function getInputHTML( $value ); 00042 00053 function msg() { 00054 $args = func_get_args(); 00055 00056 if ( $this->mParent ) { 00057 $callback = array( $this->mParent, 'msg' ); 00058 } else { 00059 $callback = 'wfMessage'; 00060 } 00061 00062 return call_user_func_array( $callback, $args ); 00063 } 00064 00075 function validate( $value, $alldata ) { 00076 if ( isset( $this->mParams['required'] ) 00077 && $this->mParams['required'] !== false 00078 && $value === '' 00079 ) { 00080 return $this->msg( 'htmlform-required' )->parse(); 00081 } 00082 00083 if ( isset( $this->mValidationCallback ) ) { 00084 return call_user_func( $this->mValidationCallback, $value, $alldata, $this->mParent ); 00085 } 00086 00087 return true; 00088 } 00089 00090 function filter( $value, $alldata ) { 00091 if ( isset( $this->mFilterCallback ) ) { 00092 $value = call_user_func( $this->mFilterCallback, $value, $alldata, $this->mParent ); 00093 } 00094 00095 return $value; 00096 } 00097 00104 protected function needsLabel() { 00105 return true; 00106 } 00107 00117 public function setShowEmptyLabel( $show ) { 00118 $this->mShowEmptyLabels = $show; 00119 } 00120 00128 function loadDataFromRequest( $request ) { 00129 if ( $request->getCheck( $this->mName ) ) { 00130 return $request->getText( $this->mName ); 00131 } else { 00132 return $this->getDefault(); 00133 } 00134 } 00135 00144 function __construct( $params ) { 00145 $this->mParams = $params; 00146 00147 # Generate the label from a message, if possible 00148 if ( isset( $params['label-message'] ) ) { 00149 $msgInfo = $params['label-message']; 00150 00151 if ( is_array( $msgInfo ) ) { 00152 $msg = array_shift( $msgInfo ); 00153 } else { 00154 $msg = $msgInfo; 00155 $msgInfo = array(); 00156 } 00157 00158 $this->mLabel = wfMessage( $msg, $msgInfo )->parse(); 00159 } elseif ( isset( $params['label'] ) ) { 00160 if ( $params['label'] === ' ' ) { 00161 // Apparently some things set   directly and in an odd format 00162 $this->mLabel = ' '; 00163 } else { 00164 $this->mLabel = htmlspecialchars( $params['label'] ); 00165 } 00166 } elseif ( isset( $params['label-raw'] ) ) { 00167 $this->mLabel = $params['label-raw']; 00168 } 00169 00170 $this->mName = "wp{$params['fieldname']}"; 00171 if ( isset( $params['name'] ) ) { 00172 $this->mName = $params['name']; 00173 } 00174 00175 $validName = Sanitizer::escapeId( $this->mName ); 00176 if ( $this->mName != $validName && !isset( $params['nodata'] ) ) { 00177 throw new MWException( "Invalid name '{$this->mName}' passed to " . __METHOD__ ); 00178 } 00179 00180 $this->mID = "mw-input-{$this->mName}"; 00181 00182 if ( isset( $params['default'] ) ) { 00183 $this->mDefault = $params['default']; 00184 } 00185 00186 if ( isset( $params['id'] ) ) { 00187 $id = $params['id']; 00188 $validId = Sanitizer::escapeId( $id ); 00189 00190 if ( $id != $validId ) { 00191 throw new MWException( "Invalid id '$id' passed to " . __METHOD__ ); 00192 } 00193 00194 $this->mID = $id; 00195 } 00196 00197 if ( isset( $params['cssclass'] ) ) { 00198 $this->mClass = $params['cssclass']; 00199 } 00200 00201 if ( isset( $params['validation-callback'] ) ) { 00202 $this->mValidationCallback = $params['validation-callback']; 00203 } 00204 00205 if ( isset( $params['filter-callback'] ) ) { 00206 $this->mFilterCallback = $params['filter-callback']; 00207 } 00208 00209 if ( isset( $params['flatlist'] ) ) { 00210 $this->mClass .= ' mw-htmlform-flatlist'; 00211 } 00212 00213 if ( isset( $params['hidelabel'] ) ) { 00214 $this->mShowEmptyLabels = false; 00215 } 00216 } 00217 00226 function getTableRow( $value ) { 00227 list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value ); 00228 $inputHtml = $this->getInputHTML( $value ); 00229 $fieldType = get_class( $this ); 00230 $helptext = $this->getHelpTextHtmlTable( $this->getHelpText() ); 00231 $cellAttributes = array(); 00232 00233 if ( !empty( $this->mParams['vertical-label'] ) ) { 00234 $cellAttributes['colspan'] = 2; 00235 $verticalLabel = true; 00236 } else { 00237 $verticalLabel = false; 00238 } 00239 00240 $label = $this->getLabelHtml( $cellAttributes ); 00241 00242 $field = Html::rawElement( 00243 'td', 00244 array( 'class' => 'mw-input' ) + $cellAttributes, 00245 $inputHtml . "\n$errors" 00246 ); 00247 00248 if ( $verticalLabel ) { 00249 $html = Html::rawElement( 'tr', array( 'class' => 'mw-htmlform-vertical-label' ), $label ); 00250 $html .= Html::rawElement( 'tr', 00251 array( 'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass" ), 00252 $field ); 00253 } else { 00254 $html = 00255 Html::rawElement( 'tr', 00256 array( 'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass" ), 00257 $label . $field ); 00258 } 00259 00260 return $html . $helptext; 00261 } 00262 00272 public function getDiv( $value ) { 00273 list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value ); 00274 $inputHtml = $this->getInputHTML( $value ); 00275 $fieldType = get_class( $this ); 00276 $helptext = $this->getHelpTextHtmlDiv( $this->getHelpText() ); 00277 $cellAttributes = array(); 00278 $label = $this->getLabelHtml( $cellAttributes ); 00279 00280 $outerDivClass = array( 00281 'mw-input', 00282 'mw-htmlform-nolabel' => ( $label === '' ) 00283 ); 00284 00285 $field = Html::rawElement( 00286 'div', 00287 array( 'class' => $outerDivClass ) + $cellAttributes, 00288 $inputHtml . "\n$errors" 00289 ); 00290 $divCssClasses = array( "mw-htmlform-field-$fieldType", $this->mClass, $errorClass ); 00291 if ( $this->mParent->isVForm() ) { 00292 $divCssClasses[] = 'mw-ui-vform-div'; 00293 } 00294 $html = Html::rawElement( 'div', array( 'class' => $divCssClasses ), $label . $field ); 00295 $html .= $helptext; 00296 00297 return $html; 00298 } 00299 00309 public function getRaw( $value ) { 00310 list( $errors, ) = $this->getErrorsAndErrorClass( $value ); 00311 $inputHtml = $this->getInputHTML( $value ); 00312 $helptext = $this->getHelpTextHtmlRaw( $this->getHelpText() ); 00313 $cellAttributes = array(); 00314 $label = $this->getLabelHtml( $cellAttributes ); 00315 00316 $html = "\n$errors"; 00317 $html .= $label; 00318 $html .= $inputHtml; 00319 $html .= $helptext; 00320 00321 return $html; 00322 } 00323 00331 public function getHelpTextHtmlTable( $helptext ) { 00332 if ( is_null( $helptext ) ) { 00333 return ''; 00334 } 00335 00336 $row = Html::rawElement( 'td', array( 'colspan' => 2, 'class' => 'htmlform-tip' ), $helptext ); 00337 $row = Html::rawElement( 'tr', array(), $row ); 00338 00339 return $row; 00340 } 00341 00350 public function getHelpTextHtmlDiv( $helptext ) { 00351 if ( is_null( $helptext ) ) { 00352 return ''; 00353 } 00354 00355 $div = Html::rawElement( 'div', array( 'class' => 'htmlform-tip' ), $helptext ); 00356 00357 return $div; 00358 } 00359 00367 public function getHelpTextHtmlRaw( $helptext ) { 00368 return $this->getHelpTextHtmlDiv( $helptext ); 00369 } 00370 00376 public function getHelpText() { 00377 $helptext = null; 00378 00379 if ( isset( $this->mParams['help-message'] ) ) { 00380 $this->mParams['help-messages'] = array( $this->mParams['help-message'] ); 00381 } 00382 00383 if ( isset( $this->mParams['help-messages'] ) ) { 00384 foreach ( $this->mParams['help-messages'] as $name ) { 00385 $helpMessage = (array)$name; 00386 $msg = $this->msg( array_shift( $helpMessage ), $helpMessage ); 00387 00388 if ( $msg->exists() ) { 00389 if ( is_null( $helptext ) ) { 00390 $helptext = ''; 00391 } else { 00392 $helptext .= $this->msg( 'word-separator' )->escaped(); // some space 00393 } 00394 $helptext .= $msg->parse(); // Append message 00395 } 00396 } 00397 } elseif ( isset( $this->mParams['help'] ) ) { 00398 $helptext = $this->mParams['help']; 00399 } 00400 00401 return $helptext; 00402 } 00403 00411 public function getErrorsAndErrorClass( $value ) { 00412 $errors = $this->validate( $value, $this->mParent->mFieldData ); 00413 00414 if ( $errors === true || 00415 ( !$this->mParent->getRequest()->wasPosted() && $this->mParent->getMethod() === 'post' ) 00416 ) { 00417 $errors = ''; 00418 $errorClass = ''; 00419 } else { 00420 $errors = self::formatErrors( $errors ); 00421 $errorClass = 'mw-htmlform-invalid-input'; 00422 } 00423 00424 return array( $errors, $errorClass ); 00425 } 00426 00427 function getLabel() { 00428 return is_null( $this->mLabel ) ? '' : $this->mLabel; 00429 } 00430 00431 function getLabelHtml( $cellAttributes = array() ) { 00432 # Don't output a for= attribute for labels with no associated input. 00433 # Kind of hacky here, possibly we don't want these to be <label>s at all. 00434 $for = array(); 00435 00436 if ( $this->needsLabel() ) { 00437 $for['for'] = $this->mID; 00438 } 00439 00440 $labelValue = trim( $this->getLabel() ); 00441 $hasLabel = false; 00442 if ( $labelValue !== ' ' && $labelValue !== '' ) { 00443 $hasLabel = true; 00444 } 00445 00446 $displayFormat = $this->mParent->getDisplayFormat(); 00447 $html = ''; 00448 00449 if ( $displayFormat === 'table' ) { 00450 $html = 00451 Html::rawElement( 'td', 00452 array( 'class' => 'mw-label' ) + $cellAttributes, 00453 Html::rawElement( 'label', $for, $labelValue ) ); 00454 } elseif ( $hasLabel || $this->mShowEmptyLabels ) { 00455 if ( $displayFormat === 'div' ) { 00456 $html = 00457 Html::rawElement( 'div', 00458 array( 'class' => 'mw-label' ) + $cellAttributes, 00459 Html::rawElement( 'label', $for, $labelValue ) ); 00460 } else { 00461 $html = Html::rawElement( 'label', $for, $labelValue ); 00462 } 00463 } 00464 00465 return $html; 00466 } 00467 00468 function getDefault() { 00469 if ( isset( $this->mDefault ) ) { 00470 return $this->mDefault; 00471 } else { 00472 return null; 00473 } 00474 } 00475 00481 public function getTooltipAndAccessKey() { 00482 if ( empty( $this->mParams['tooltip'] ) ) { 00483 return array(); 00484 } 00485 00486 return Linker::tooltipAndAccesskeyAttribs( $this->mParams['tooltip'] ); 00487 } 00488 00495 public function getAttributes( array $list ) { 00496 static $boolAttribs = array( 'disabled', 'required', 'autofocus', 'multiple', 'readonly' ); 00497 00498 $ret = array(); 00499 00500 foreach ( $list as $key ) { 00501 if ( in_array( $key, $boolAttribs ) ) { 00502 if ( !empty( $this->mParams[$key] ) ) { 00503 $ret[$key] = ''; 00504 } 00505 } elseif ( isset( $this->mParams[$key] ) ) { 00506 $ret[$key] = $this->mParams[$key]; 00507 } 00508 } 00509 00510 return $ret; 00511 } 00512 00520 private function lookupOptionsKeys( $options ) { 00521 $ret = array(); 00522 foreach ( $options as $key => $value ) { 00523 $key = $this->msg( $key )->plain(); 00524 $ret[$key] = is_array( $value ) 00525 ? $this->lookupOptionsKeys( $value ) 00526 : strval( $value ); 00527 } 00528 return $ret; 00529 } 00530 00538 static function forceToStringRecursive( $array ) { 00539 if ( is_array( $array ) ) { 00540 return array_map( array( __CLASS__, 'forceToStringRecursive' ), $array ); 00541 } else { 00542 return strval( $array ); 00543 } 00544 } 00545 00552 public function getOptions() { 00553 if ( $this->mOptions === false ) { 00554 if ( array_key_exists( 'options-messages', $this->mParams ) ) { 00555 $this->mOptions = $this->lookupOptionsKeys( $this->mParams['options-messages'] ); 00556 } elseif ( array_key_exists( 'options', $this->mParams ) ) { 00557 $this->mOptionsLabelsNotFromMessage = true; 00558 $this->mOptions = self::forceToStringRecursive( $this->mParams['options'] ); 00559 } elseif ( array_key_exists( 'options-message', $this->mParams ) ) { 00561 $message = $this->msg( $this->mParams['options-message'] )->inContentLanguage()->plain(); 00562 00563 $optgroup = false; 00564 $this->mOptions = array(); 00565 foreach ( explode( "\n", $message ) as $option ) { 00566 $value = trim( $option ); 00567 if ( $value == '' ) { 00568 continue; 00569 } elseif ( substr( $value, 0, 1 ) == '*' && substr( $value, 1, 1 ) != '*' ) { 00570 # A new group is starting... 00571 $value = trim( substr( $value, 1 ) ); 00572 $optgroup = $value; 00573 } elseif ( substr( $value, 0, 2 ) == '**' ) { 00574 # groupmember 00575 $opt = trim( substr( $value, 2 ) ); 00576 if ( $optgroup === false ) { 00577 $this->mOptions[$opt] = $opt; 00578 } else { 00579 $this->mOptions[$optgroup][$opt] = $opt; 00580 } 00581 } else { 00582 # groupless reason list 00583 $optgroup = false; 00584 $this->mOptions[$option] = $option; 00585 } 00586 } 00587 } else { 00588 $this->mOptions = null; 00589 } 00590 } 00591 00592 return $this->mOptions; 00593 } 00594 00603 public static function flattenOptions( $options ) { 00604 $flatOpts = array(); 00605 00606 foreach ( $options as $value ) { 00607 if ( is_array( $value ) ) { 00608 $flatOpts = array_merge( $flatOpts, self::flattenOptions( $value ) ); 00609 } else { 00610 $flatOpts[] = $value; 00611 } 00612 } 00613 00614 return $flatOpts; 00615 } 00616 00624 protected static function formatErrors( $errors ) { 00625 if ( is_array( $errors ) && count( $errors ) === 1 ) { 00626 $errors = array_shift( $errors ); 00627 } 00628 00629 if ( is_array( $errors ) ) { 00630 $lines = array(); 00631 foreach ( $errors as $error ) { 00632 if ( $error instanceof Message ) { 00633 $lines[] = Html::rawElement( 'li', array(), $error->parse() ); 00634 } else { 00635 $lines[] = Html::rawElement( 'li', array(), $error ); 00636 } 00637 } 00638 00639 return Html::rawElement( 'ul', array( 'class' => 'error' ), implode( "\n", $lines ) ); 00640 } else { 00641 if ( $errors instanceof Message ) { 00642 $errors = $errors->parse(); 00643 } 00644 00645 return Html::rawElement( 'span', array( 'class' => 'error' ), $errors ); 00646 } 00647 } 00648 }