[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * The parent class to generate form fields. Any field type should 5 * be a subclass of this. 6 */ 7 abstract class HTMLFormField { 8 public $mParams; 9 10 protected $mValidationCallback; 11 protected $mFilterCallback; 12 protected $mName; 13 protected $mLabel; # String label. Set on construction 14 protected $mID; 15 protected $mClass = ''; 16 protected $mHelpClass = false; 17 protected $mDefault; 18 protected $mOptions = false; 19 protected $mOptionsLabelsNotFromMessage = false; 20 protected $mHideIf = null; 21 22 /** 23 * @var bool If true will generate an empty div element with no label 24 * @since 1.22 25 */ 26 protected $mShowEmptyLabels = true; 27 28 /** 29 * @var HTMLForm 30 */ 31 public $mParent; 32 33 /** 34 * This function must be implemented to return the HTML to generate 35 * the input object itself. It should not implement the surrounding 36 * table cells/rows, or labels/help messages. 37 * 38 * @param string $value The value to set the input to; eg a default 39 * text for a text input. 40 * 41 * @return string Valid HTML. 42 */ 43 abstract function getInputHTML( $value ); 44 45 /** 46 * Get a translated interface message 47 * 48 * This is a wrapper around $this->mParent->msg() if $this->mParent is set 49 * and wfMessage() otherwise. 50 * 51 * Parameters are the same as wfMessage(). 52 * 53 * @return Message 54 */ 55 function msg() { 56 $args = func_get_args(); 57 58 if ( $this->mParent ) { 59 $callback = array( $this->mParent, 'msg' ); 60 } else { 61 $callback = 'wfMessage'; 62 } 63 64 return call_user_func_array( $callback, $args ); 65 } 66 67 68 /** 69 * Fetch a field value from $alldata for the closest field matching a given 70 * name. 71 * 72 * This is complex because it needs to handle array fields like the user 73 * would expect. The general algorithm is to look for $name as a sibling 74 * of $this, then a sibling of $this's parent, and so on. Keeping in mind 75 * that $name itself might be referencing an array. 76 * 77 * @param array $alldata 78 * @param string $name 79 * @return string 80 */ 81 protected function getNearestFieldByName( $alldata, $name ) { 82 $tmp = $this->mName; 83 $thisKeys = array(); 84 while ( preg_match( '/^(.+)\[([^\]]+)\]$/', $tmp, $m ) ) { 85 array_unshift( $thisKeys, $m[2] ); 86 $tmp = $m[1]; 87 } 88 if ( substr( $tmp, 0, 2 ) == 'wp' && 89 !isset( $alldata[$tmp] ) && 90 isset( $alldata[substr( $tmp, 2 )] ) 91 ) { 92 // Adjust for name mangling. 93 $tmp = substr( $tmp, 2 ); 94 } 95 array_unshift( $thisKeys, $tmp ); 96 97 $tmp = $name; 98 $nameKeys = array(); 99 while ( preg_match( '/^(.+)\[([^\]]+)\]$/', $tmp, $m ) ) { 100 array_unshift( $nameKeys, $m[2] ); 101 $tmp = $m[1]; 102 } 103 array_unshift( $nameKeys, $tmp ); 104 105 $testValue = ''; 106 for ( $i = count( $thisKeys ) - 1; $i >= 0; $i-- ) { 107 $keys = array_merge( array_slice( $thisKeys, 0, $i ), $nameKeys ); 108 $data = $alldata; 109 while ( $keys ) { 110 $key = array_shift( $keys ); 111 if ( !is_array( $data ) || !isset( $data[$key] ) ) { 112 continue 2; 113 } 114 $data = $data[$key]; 115 } 116 $testValue = (string)$data; 117 break; 118 } 119 120 return $testValue; 121 } 122 123 /** 124 * Helper function for isHidden to handle recursive data structures. 125 * 126 * @param array $alldata 127 * @param array $params 128 * @return bool 129 */ 130 protected function isHiddenRecurse( array $alldata, array $params ) { 131 $origParams = $params; 132 $op = array_shift( $params ); 133 134 try { 135 switch ( $op ) { 136 case 'AND': 137 foreach ( $params as $i => $p ) { 138 if ( !is_array( $p ) ) { 139 throw new MWException( 140 "Expected array, found " . gettype( $p ) . " at index $i" 141 ); 142 } 143 if ( !$this->isHiddenRecurse( $alldata, $p ) ) { 144 return false; 145 } 146 } 147 return true; 148 149 case 'OR': 150 foreach ( $params as $p ) { 151 if ( !is_array( $p ) ) { 152 throw new MWException( 153 "Expected array, found " . gettype( $p ) . " at index $i" 154 ); 155 } 156 if ( $this->isHiddenRecurse( $alldata, $p ) ) { 157 return true; 158 } 159 } 160 return false; 161 162 case 'NAND': 163 foreach ( $params as $i => $p ) { 164 if ( !is_array( $p ) ) { 165 throw new MWException( 166 "Expected array, found " . gettype( $p ) . " at index $i" 167 ); 168 } 169 if ( !$this->isHiddenRecurse( $alldata, $p ) ) { 170 return true; 171 } 172 } 173 return false; 174 175 case 'NOR': 176 foreach ( $params as $p ) { 177 if ( !is_array( $p ) ) { 178 throw new MWException( 179 "Expected array, found " . gettype( $p ) . " at index $i" 180 ); 181 } 182 if ( $this->isHiddenRecurse( $alldata, $p ) ) { 183 return false; 184 } 185 } 186 return true; 187 188 case 'NOT': 189 if ( count( $params ) !== 1 ) { 190 throw new MWException( "NOT takes exactly one parameter" ); 191 } 192 $p = $params[0]; 193 if ( !is_array( $p ) ) { 194 throw new MWException( 195 "Expected array, found " . gettype( $p ) . " at index 0" 196 ); 197 } 198 return !$this->isHiddenRecurse( $alldata, $p ); 199 200 case '===': 201 case '!==': 202 if ( count( $params ) !== 2 ) { 203 throw new MWException( "$op takes exactly two parameters" ); 204 } 205 list( $field, $value ) = $params; 206 if ( !is_string( $field ) || !is_string( $value ) ) { 207 throw new MWException( "Parameters for $op must be strings" ); 208 } 209 $testValue = $this->getNearestFieldByName( $alldata, $field ); 210 switch ( $op ) { 211 case '===': 212 return ( $value === $testValue ); 213 case '!==': 214 return ( $value !== $testValue ); 215 } 216 217 default: 218 throw new MWException( "Unknown operation" ); 219 } 220 } catch ( MWException $ex ) { 221 throw new MWException( 222 "Invalid hide-if specification for $this->mName: " . 223 $ex->getMessage() . " in " . var_export( $origParams, true ), 224 0, $ex 225 ); 226 } 227 } 228 229 /** 230 * Test whether this field is supposed to be hidden, based on the values of 231 * the other form fields. 232 * 233 * @since 1.23 234 * @param array $alldata The data collected from the form 235 * @return bool 236 */ 237 function isHidden( $alldata ) { 238 if ( !$this->mHideIf ) { 239 return false; 240 } 241 242 return $this->isHiddenRecurse( $alldata, $this->mHideIf ); 243 } 244 245 /** 246 * Override this function if the control can somehow trigger a form 247 * submission that shouldn't actually submit the HTMLForm. 248 * 249 * @since 1.23 250 * @param string|array $value The value the field was submitted with 251 * @param array $alldata The data collected from the form 252 * 253 * @return bool True to cancel the submission 254 */ 255 function cancelSubmit( $value, $alldata ) { 256 return false; 257 } 258 259 /** 260 * Override this function to add specific validation checks on the 261 * field input. Don't forget to call parent::validate() to ensure 262 * that the user-defined callback mValidationCallback is still run 263 * 264 * @param string|array $value The value the field was submitted with 265 * @param array $alldata The data collected from the form 266 * 267 * @return bool|string True on success, or String error to display, or 268 * false to fail validation without displaying an error. 269 */ 270 function validate( $value, $alldata ) { 271 if ( $this->isHidden( $alldata ) ) { 272 return true; 273 } 274 275 if ( isset( $this->mParams['required'] ) 276 && $this->mParams['required'] !== false 277 && $value === '' 278 ) { 279 return $this->msg( 'htmlform-required' )->parse(); 280 } 281 282 if ( isset( $this->mValidationCallback ) ) { 283 return call_user_func( $this->mValidationCallback, $value, $alldata, $this->mParent ); 284 } 285 286 return true; 287 } 288 289 function filter( $value, $alldata ) { 290 if ( isset( $this->mFilterCallback ) ) { 291 $value = call_user_func( $this->mFilterCallback, $value, $alldata, $this->mParent ); 292 } 293 294 return $value; 295 } 296 297 /** 298 * Should this field have a label, or is there no input element with the 299 * appropriate id for the label to point to? 300 * 301 * @return bool True to output a label, false to suppress 302 */ 303 protected function needsLabel() { 304 return true; 305 } 306 307 /** 308 * Tell the field whether to generate a separate label element if its label 309 * is blank. 310 * 311 * @since 1.22 312 * 313 * @param bool $show Set to false to not generate a label. 314 * @return void 315 */ 316 public function setShowEmptyLabel( $show ) { 317 $this->mShowEmptyLabels = $show; 318 } 319 320 /** 321 * Get the value that this input has been set to from a posted form, 322 * or the input's default value if it has not been set. 323 * 324 * @param WebRequest $request 325 * @return string The value 326 */ 327 function loadDataFromRequest( $request ) { 328 if ( $request->getCheck( $this->mName ) ) { 329 return $request->getText( $this->mName ); 330 } else { 331 return $this->getDefault(); 332 } 333 } 334 335 /** 336 * Initialise the object 337 * 338 * @param array $params Associative Array. See HTMLForm doc for syntax. 339 * 340 * @since 1.22 The 'label' attribute no longer accepts raw HTML, use 'label-raw' instead 341 * @throws MWException 342 */ 343 function __construct( $params ) { 344 $this->mParams = $params; 345 346 # Generate the label from a message, if possible 347 if ( isset( $params['label-message'] ) ) { 348 $msgInfo = $params['label-message']; 349 350 if ( is_array( $msgInfo ) ) { 351 $msg = array_shift( $msgInfo ); 352 } else { 353 $msg = $msgInfo; 354 $msgInfo = array(); 355 } 356 357 $this->mLabel = wfMessage( $msg, $msgInfo )->parse(); 358 } elseif ( isset( $params['label'] ) ) { 359 if ( $params['label'] === ' ' ) { 360 // Apparently some things set   directly and in an odd format 361 $this->mLabel = ' '; 362 } else { 363 $this->mLabel = htmlspecialchars( $params['label'] ); 364 } 365 } elseif ( isset( $params['label-raw'] ) ) { 366 $this->mLabel = $params['label-raw']; 367 } 368 369 $this->mName = "wp{$params['fieldname']}"; 370 if ( isset( $params['name'] ) ) { 371 $this->mName = $params['name']; 372 } 373 374 $validName = Sanitizer::escapeId( $this->mName ); 375 $validName = str_replace( array( '.5B', '.5D' ), array( '[', ']' ), $validName ); 376 if ( $this->mName != $validName && !isset( $params['nodata'] ) ) { 377 throw new MWException( "Invalid name '{$this->mName}' passed to " . __METHOD__ ); 378 } 379 380 $this->mID = "mw-input-{$this->mName}"; 381 382 if ( isset( $params['default'] ) ) { 383 $this->mDefault = $params['default']; 384 } 385 386 if ( isset( $params['id'] ) ) { 387 $id = $params['id']; 388 $validId = Sanitizer::escapeId( $id ); 389 390 if ( $id != $validId ) { 391 throw new MWException( "Invalid id '$id' passed to " . __METHOD__ ); 392 } 393 394 $this->mID = $id; 395 } 396 397 if ( isset( $params['cssclass'] ) ) { 398 $this->mClass = $params['cssclass']; 399 } 400 401 if ( isset( $params['csshelpclass'] ) ) { 402 $this->mHelpClass = $params['csshelpclass']; 403 } 404 405 if ( isset( $params['validation-callback'] ) ) { 406 $this->mValidationCallback = $params['validation-callback']; 407 } 408 409 if ( isset( $params['filter-callback'] ) ) { 410 $this->mFilterCallback = $params['filter-callback']; 411 } 412 413 if ( isset( $params['flatlist'] ) ) { 414 $this->mClass .= ' mw-htmlform-flatlist'; 415 } 416 417 if ( isset( $params['hidelabel'] ) ) { 418 $this->mShowEmptyLabels = false; 419 } 420 421 if ( isset( $params['hide-if'] ) ) { 422 $this->mHideIf = $params['hide-if']; 423 } 424 } 425 426 /** 427 * Get the complete table row for the input, including help text, 428 * labels, and whatever. 429 * 430 * @param string $value The value to set the input to. 431 * 432 * @return string Complete HTML table row. 433 */ 434 function getTableRow( $value ) { 435 list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value ); 436 $inputHtml = $this->getInputHTML( $value ); 437 $fieldType = get_class( $this ); 438 $helptext = $this->getHelpTextHtmlTable( $this->getHelpText() ); 439 $cellAttributes = array(); 440 $rowAttributes = array(); 441 $rowClasses = ''; 442 443 if ( !empty( $this->mParams['vertical-label'] ) ) { 444 $cellAttributes['colspan'] = 2; 445 $verticalLabel = true; 446 } else { 447 $verticalLabel = false; 448 } 449 450 $label = $this->getLabelHtml( $cellAttributes ); 451 452 $field = Html::rawElement( 453 'td', 454 array( 'class' => 'mw-input' ) + $cellAttributes, 455 $inputHtml . "\n$errors" 456 ); 457 458 if ( $this->mHideIf ) { 459 $rowAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf ); 460 $rowClasses .= ' mw-htmlform-hide-if'; 461 } 462 463 if ( $verticalLabel ) { 464 $html = Html::rawElement( 'tr', 465 $rowAttributes + array( 'class' => "mw-htmlform-vertical-label $rowClasses" ), $label ); 466 $html .= Html::rawElement( 'tr', 467 $rowAttributes + array( 468 'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass $rowClasses" 469 ), 470 $field ); 471 } else { 472 $html = 473 Html::rawElement( 'tr', 474 $rowAttributes + array( 475 'class' => "mw-htmlform-field-$fieldType {$this->mClass} $errorClass $rowClasses" 476 ), 477 $label . $field ); 478 } 479 480 return $html . $helptext; 481 } 482 483 /** 484 * Get the complete div for the input, including help text, 485 * labels, and whatever. 486 * @since 1.20 487 * 488 * @param string $value The value to set the input to. 489 * 490 * @return string Complete HTML table row. 491 */ 492 public function getDiv( $value ) { 493 list( $errors, $errorClass ) = $this->getErrorsAndErrorClass( $value ); 494 $inputHtml = $this->getInputHTML( $value ); 495 $fieldType = get_class( $this ); 496 $helptext = $this->getHelpTextHtmlDiv( $this->getHelpText() ); 497 $cellAttributes = array(); 498 $label = $this->getLabelHtml( $cellAttributes ); 499 500 $outerDivClass = array( 501 'mw-input', 502 'mw-htmlform-nolabel' => ( $label === '' ) 503 ); 504 505 $field = Html::rawElement( 506 'div', 507 array( 'class' => $outerDivClass ) + $cellAttributes, 508 $inputHtml . "\n$errors" 509 ); 510 $divCssClasses = array( "mw-htmlform-field-$fieldType", $this->mClass, $errorClass ); 511 if ( $this->mParent->isVForm() ) { 512 $divCssClasses[] = 'mw-ui-vform-field'; 513 } 514 515 $wrapperAttributes = array( 516 'class' => $divCssClasses, 517 ); 518 if ( $this->mHideIf ) { 519 $wrapperAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf ); 520 $wrapperAttributes['class'][] = ' mw-htmlform-hide-if'; 521 } 522 $html = Html::rawElement( 'div', $wrapperAttributes, $label . $field ); 523 $html .= $helptext; 524 525 return $html; 526 } 527 528 /** 529 * Get the complete raw fields for the input, including help text, 530 * labels, and whatever. 531 * @since 1.20 532 * 533 * @param string $value The value to set the input to. 534 * 535 * @return string Complete HTML table row. 536 */ 537 public function getRaw( $value ) { 538 list( $errors, ) = $this->getErrorsAndErrorClass( $value ); 539 $inputHtml = $this->getInputHTML( $value ); 540 $helptext = $this->getHelpTextHtmlRaw( $this->getHelpText() ); 541 $cellAttributes = array(); 542 $label = $this->getLabelHtml( $cellAttributes ); 543 544 $html = "\n$errors"; 545 $html .= $label; 546 $html .= $inputHtml; 547 $html .= $helptext; 548 549 return $html; 550 } 551 552 /** 553 * Generate help text HTML in table format 554 * @since 1.20 555 * 556 * @param string|null $helptext 557 * @return string 558 */ 559 public function getHelpTextHtmlTable( $helptext ) { 560 if ( is_null( $helptext ) ) { 561 return ''; 562 } 563 564 $rowAttributes = array(); 565 if ( $this->mHideIf ) { 566 $rowAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf ); 567 $rowAttributes['class'] = 'mw-htmlform-hide-if'; 568 } 569 570 $tdClasses = array( 'htmlform-tip' ); 571 if ( $this->mHelpClass !== false ) { 572 $tdClasses[] = $this->mHelpClass; 573 } 574 $row = Html::rawElement( 'td', array( 'colspan' => 2, 'class' => $tdClasses ), $helptext ); 575 $row = Html::rawElement( 'tr', $rowAttributes, $row ); 576 577 return $row; 578 } 579 580 /** 581 * Generate help text HTML in div format 582 * @since 1.20 583 * 584 * @param string|null $helptext 585 * 586 * @return string 587 */ 588 public function getHelpTextHtmlDiv( $helptext ) { 589 if ( is_null( $helptext ) ) { 590 return ''; 591 } 592 593 $wrapperAttributes = array( 594 'class' => 'htmlform-tip', 595 ); 596 if ( $this->mHelpClass !== false ) { 597 $wrapperAttributes['class'] .= " {$this->mHelpClass}"; 598 } 599 if ( $this->mHideIf ) { 600 $wrapperAttributes['data-hide-if'] = FormatJson::encode( $this->mHideIf ); 601 $wrapperAttributes['class'] .= ' mw-htmlform-hide-if'; 602 } 603 $div = Html::rawElement( 'div', $wrapperAttributes, $helptext ); 604 605 return $div; 606 } 607 608 /** 609 * Generate help text HTML formatted for raw output 610 * @since 1.20 611 * 612 * @param string|null $helptext 613 * @return string 614 */ 615 public function getHelpTextHtmlRaw( $helptext ) { 616 return $this->getHelpTextHtmlDiv( $helptext ); 617 } 618 619 /** 620 * Determine the help text to display 621 * @since 1.20 622 * @return string 623 */ 624 public function getHelpText() { 625 $helptext = null; 626 627 if ( isset( $this->mParams['help-message'] ) ) { 628 $this->mParams['help-messages'] = array( $this->mParams['help-message'] ); 629 } 630 631 if ( isset( $this->mParams['help-messages'] ) ) { 632 foreach ( $this->mParams['help-messages'] as $name ) { 633 $helpMessage = (array)$name; 634 $msg = $this->msg( array_shift( $helpMessage ), $helpMessage ); 635 636 if ( $msg->exists() ) { 637 if ( is_null( $helptext ) ) { 638 $helptext = ''; 639 } else { 640 $helptext .= $this->msg( 'word-separator' )->escaped(); // some space 641 } 642 $helptext .= $msg->parse(); // Append message 643 } 644 } 645 } elseif ( isset( $this->mParams['help'] ) ) { 646 $helptext = $this->mParams['help']; 647 } 648 649 return $helptext; 650 } 651 652 /** 653 * Determine form errors to display and their classes 654 * @since 1.20 655 * 656 * @param string $value The value of the input 657 * @return array 658 */ 659 public function getErrorsAndErrorClass( $value ) { 660 $errors = $this->validate( $value, $this->mParent->mFieldData ); 661 662 if ( is_bool( $errors ) || !$this->mParent->wasSubmitted() ) { 663 $errors = ''; 664 $errorClass = ''; 665 } else { 666 $errors = self::formatErrors( $errors ); 667 $errorClass = 'mw-htmlform-invalid-input'; 668 } 669 670 return array( $errors, $errorClass ); 671 } 672 673 function getLabel() { 674 return is_null( $this->mLabel ) ? '' : $this->mLabel; 675 } 676 677 function getLabelHtml( $cellAttributes = array() ) { 678 # Don't output a for= attribute for labels with no associated input. 679 # Kind of hacky here, possibly we don't want these to be <label>s at all. 680 $for = array(); 681 682 if ( $this->needsLabel() ) { 683 $for['for'] = $this->mID; 684 } 685 686 $labelValue = trim( $this->getLabel() ); 687 $hasLabel = false; 688 if ( $labelValue !== ' ' && $labelValue !== '' ) { 689 $hasLabel = true; 690 } 691 692 $displayFormat = $this->mParent->getDisplayFormat(); 693 $html = ''; 694 695 if ( $displayFormat === 'table' ) { 696 $html = 697 Html::rawElement( 'td', 698 array( 'class' => 'mw-label' ) + $cellAttributes, 699 Html::rawElement( 'label', $for, $labelValue ) ); 700 } elseif ( $hasLabel || $this->mShowEmptyLabels ) { 701 if ( $displayFormat === 'div' ) { 702 $html = 703 Html::rawElement( 'div', 704 array( 'class' => 'mw-label' ) + $cellAttributes, 705 Html::rawElement( 'label', $for, $labelValue ) ); 706 } else { 707 $html = Html::rawElement( 'label', $for, $labelValue ); 708 } 709 } 710 711 return $html; 712 } 713 714 function getDefault() { 715 if ( isset( $this->mDefault ) ) { 716 return $this->mDefault; 717 } else { 718 return null; 719 } 720 } 721 722 /** 723 * Returns the attributes required for the tooltip and accesskey. 724 * 725 * @return array Attributes 726 */ 727 public function getTooltipAndAccessKey() { 728 if ( empty( $this->mParams['tooltip'] ) ) { 729 return array(); 730 } 731 732 return Linker::tooltipAndAccesskeyAttribs( $this->mParams['tooltip'] ); 733 } 734 735 /** 736 * Returns the given attributes from the parameters 737 * 738 * @param array $list List of attributes to get 739 * @return array Attributes 740 */ 741 public function getAttributes( array $list ) { 742 static $boolAttribs = array( 'disabled', 'required', 'autofocus', 'multiple', 'readonly' ); 743 744 $ret = array(); 745 746 foreach ( $list as $key ) { 747 if ( in_array( $key, $boolAttribs ) ) { 748 if ( !empty( $this->mParams[$key] ) ) { 749 $ret[$key] = ''; 750 } 751 } elseif ( isset( $this->mParams[$key] ) ) { 752 $ret[$key] = $this->mParams[$key]; 753 } 754 } 755 756 return $ret; 757 } 758 759 /** 760 * Given an array of msg-key => value mappings, returns an array with keys 761 * being the message texts. It also forces values to strings. 762 * 763 * @param array $options 764 * @return array 765 */ 766 private function lookupOptionsKeys( $options ) { 767 $ret = array(); 768 foreach ( $options as $key => $value ) { 769 $key = $this->msg( $key )->plain(); 770 $ret[$key] = is_array( $value ) 771 ? $this->lookupOptionsKeys( $value ) 772 : strval( $value ); 773 } 774 return $ret; 775 } 776 777 /** 778 * Recursively forces values in an array to strings, because issues arise 779 * with integer 0 as a value. 780 * 781 * @param array $array 782 * @return array 783 */ 784 static function forceToStringRecursive( $array ) { 785 if ( is_array( $array ) ) { 786 return array_map( array( __CLASS__, 'forceToStringRecursive' ), $array ); 787 } else { 788 return strval( $array ); 789 } 790 } 791 792 /** 793 * Fetch the array of options from the field's parameters. In order, this 794 * checks 'options-messages', 'options', then 'options-message'. 795 * 796 * @return array|null Options array 797 */ 798 public function getOptions() { 799 if ( $this->mOptions === false ) { 800 if ( array_key_exists( 'options-messages', $this->mParams ) ) { 801 $this->mOptions = $this->lookupOptionsKeys( $this->mParams['options-messages'] ); 802 } elseif ( array_key_exists( 'options', $this->mParams ) ) { 803 $this->mOptionsLabelsNotFromMessage = true; 804 $this->mOptions = self::forceToStringRecursive( $this->mParams['options'] ); 805 } elseif ( array_key_exists( 'options-message', $this->mParams ) ) { 806 /** @todo This is copied from Xml::listDropDown(), deprecate/avoid duplication? */ 807 $message = $this->msg( $this->mParams['options-message'] )->inContentLanguage()->plain(); 808 809 $optgroup = false; 810 $this->mOptions = array(); 811 foreach ( explode( "\n", $message ) as $option ) { 812 $value = trim( $option ); 813 if ( $value == '' ) { 814 continue; 815 } elseif ( substr( $value, 0, 1 ) == '*' && substr( $value, 1, 1 ) != '*' ) { 816 # A new group is starting... 817 $value = trim( substr( $value, 1 ) ); 818 $optgroup = $value; 819 } elseif ( substr( $value, 0, 2 ) == '**' ) { 820 # groupmember 821 $opt = trim( substr( $value, 2 ) ); 822 if ( $optgroup === false ) { 823 $this->mOptions[$opt] = $opt; 824 } else { 825 $this->mOptions[$optgroup][$opt] = $opt; 826 } 827 } else { 828 # groupless reason list 829 $optgroup = false; 830 $this->mOptions[$option] = $option; 831 } 832 } 833 } else { 834 $this->mOptions = null; 835 } 836 } 837 838 return $this->mOptions; 839 } 840 841 /** 842 * flatten an array of options to a single array, for instance, 843 * a set of "<options>" inside "<optgroups>". 844 * 845 * @param array $options Associative Array with values either Strings or Arrays 846 * @return array Flattened input 847 */ 848 public static function flattenOptions( $options ) { 849 $flatOpts = array(); 850 851 foreach ( $options as $value ) { 852 if ( is_array( $value ) ) { 853 $flatOpts = array_merge( $flatOpts, self::flattenOptions( $value ) ); 854 } else { 855 $flatOpts[] = $value; 856 } 857 } 858 859 return $flatOpts; 860 } 861 862 /** 863 * Formats one or more errors as accepted by field validation-callback. 864 * 865 * @param string|Message|array $errors Array of strings or Message instances 866 * @return string HTML 867 * @since 1.18 868 */ 869 protected static function formatErrors( $errors ) { 870 if ( is_array( $errors ) && count( $errors ) === 1 ) { 871 $errors = array_shift( $errors ); 872 } 873 874 if ( is_array( $errors ) ) { 875 $lines = array(); 876 foreach ( $errors as $error ) { 877 if ( $error instanceof Message ) { 878 $lines[] = Html::rawElement( 'li', array(), $error->parse() ); 879 } else { 880 $lines[] = Html::rawElement( 'li', array(), $error ); 881 } 882 } 883 884 return Html::rawElement( 'ul', array( 'class' => 'error' ), implode( "\n", $lines ) ); 885 } else { 886 if ( $errors instanceof Message ) { 887 $errors = $errors->parse(); 888 } 889 890 return Html::rawElement( 'span', array( 'class' => 'error' ), $errors ); 891 } 892 } 893 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |