[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Classes for InputBox extension 4 * 5 * @file 6 * @ingroup Extensions 7 */ 8 9 // InputBox class 10 class InputBox { 11 12 /* Fields */ 13 14 private $mParser; 15 private $mType = ''; 16 private $mWidth = 50; 17 private $mPreload = ''; 18 private $mEditIntro = ''; 19 private $mSummary = ''; 20 private $mNosummary = ''; 21 private $mMinor = ''; 22 private $mPage = ''; 23 private $mBR = 'yes'; 24 private $mDefaultText = ''; 25 private $mPlaceholderText = ''; 26 private $mBGColor = 'transparent'; 27 private $mButtonLabel = ''; 28 private $mSearchButtonLabel = ''; 29 private $mFullTextButton = ''; 30 private $mLabelText = ''; 31 private $mHidden = ''; 32 private $mNamespaces = ''; 33 private $mID = ''; 34 private $mInline = false; 35 private $mPrefix = ''; 36 private $mDir = ''; 37 38 /* Functions */ 39 40 public function __construct( $parser ) { 41 $this->mParser = $parser; 42 // Default value for dir taken from the page language (bug 37018) 43 $this->mDir = $this->mParser->getTargetLanguage()->getDir(); 44 // Split caches by language, to make sure visitors do not see a cached 45 // version in a random language (since labels are in the user language) 46 $this->mParser->getOptions()->getUserLangObj(); 47 $this->mParser->getOutput()->addModuleStyles( 'ext.inputBox.styles' ); 48 } 49 50 public function render() { 51 // Handle various types 52 switch ( $this->mType ) { 53 case 'create': 54 case 'comment': 55 return $this->getCreateForm(); 56 case 'move': 57 return $this->getMoveForm(); 58 case 'commenttitle': 59 return $this->getCommentForm(); 60 case 'search': 61 return $this->getSearchForm('search'); 62 case 'fulltext': 63 return $this->getSearchForm('fulltext'); 64 case 'search2': 65 return $this->getSearchForm2(); 66 default: 67 return Xml::tags( 'div', null, 68 Xml::element( 'strong', 69 array( 70 'class' => 'error' 71 ), 72 strlen( $this->mType ) > 0 73 ? wfMessage( 'inputbox-error-bad-type', $this->mType )->text() 74 : wfMessage( 'inputbox-error-no-type' )->text() 75 ) 76 ); 77 } 78 } 79 80 /** 81 * Generate search form 82 * @param $type 83 * @return string HTML 84 */ 85 public function getSearchForm( $type ) { 86 global $wgContLang, $wgNamespaceAliases; 87 88 // Use button label fallbacks 89 if ( !$this->mButtonLabel ) { 90 $this->mButtonLabel = wfMessage( 'inputbox-tryexact' )->text(); 91 } 92 if ( !$this->mSearchButtonLabel ) { 93 $this->mSearchButtonLabel = wfMessage( 'inputbox-searchfulltext' )->text(); 94 } 95 if ( $this->mID !== '' ) { 96 $idArray = array( 'id' => Sanitizer::escapeId( $this->mID ) ); 97 } else { 98 $idArray = array(); 99 } 100 // We need a unqiue id to link <label> to checkboxes, but also 101 // want multiple <inputbox>'s to not be invalid html 102 $idRandStr = Sanitizer::escapeId( '-' . $this->mID . wfRandom(), 'noninitial' ); 103 104 // Build HTML 105 $htmlOut = Xml::openElement( 'div', 106 array( 107 'class' => 'mw-inputbox-centered', 108 'style' => $this->bgColorStyle(), 109 ) 110 ); 111 $htmlOut .= Xml::openElement( 'form', 112 array( 113 'name' => 'searchbox', 114 'class' => 'searchbox', 115 'action' => SpecialPage::getTitleFor( 'Search' )->getLocalUrl(), 116 ) + $idArray 117 ); 118 $htmlOut .= Xml::element( 'input', 119 array( 120 'class' => 'searchboxInput', 121 'name' => 'search', 122 'type' => $this->mHidden ? 'hidden' : 'text', 123 'value' => $this->mDefaultText, 124 'placeholder' => $this->mPlaceholderText, 125 'size' => $this->mWidth, 126 'dir' => $this->mDir, 127 ) 128 ); 129 130 if ( $this->mPrefix != '' ) { 131 $htmlOut .= Xml::element( 'input', 132 array( 133 'name' => 'prefix', 134 'type' => 'hidden', 135 'value' => $this->mPrefix, 136 ) 137 ); 138 } 139 140 $htmlOut .= $this->mBR; 141 142 // Determine namespace checkboxes 143 $namespacesArray = explode( ',', $this->mNamespaces ); 144 if ( $this->mNamespaces ) { 145 $namespaces = $wgContLang->getNamespaces(); 146 $nsAliases = array_merge( $wgContLang->getNamespaceAliases(), $wgNamespaceAliases ); 147 $showNamespaces = array(); 148 $checkedNS = array(); 149 # Check for valid namespaces 150 foreach ( $namespacesArray as $userNS ) { 151 $userNS = trim( $userNS ); # no whitespace 152 153 # Namespace needs to be checked if flagged with "**" 154 if ( strpos( $userNS, '**' ) ) { 155 $userNS = str_replace( '**', '', $userNS ); 156 $checkedNS[$userNS] = true; 157 } 158 159 $mainMsg = wfMessage( 'inputbox-ns-main' )->inContentLanguage()->text(); 160 if ( $userNS == 'Main' || $userNS == $mainMsg ) { 161 $i = 0; 162 } elseif ( array_search( $userNS, $namespaces ) ) { 163 $i = array_search( $userNS, $namespaces ); 164 } elseif ( isset( $nsAliases[$userNS] ) ) { 165 $i = $nsAliases[$userNS]; 166 } else { 167 continue; # Namespace not recognized, skip 168 } 169 $showNamespaces[$i] = $userNS; 170 if ( isset( $checkedNS[$userNS] ) && $checkedNS[$userNS] ) { 171 $checkedNS[$i] = true; 172 } 173 } 174 175 # Show valid namespaces 176 foreach ( $showNamespaces as $i => $name ) { 177 $checked = array(); 178 // Namespace flagged with "**" or if it's the only one 179 if ( ( isset( $checkedNS[$i] ) && $checkedNS[$i] ) || count( $showNamespaces ) == 1 ) { 180 $checked = array( 'checked' => 'checked' ); 181 } 182 183 if ( count( $showNamespaces ) == 1 ) { 184 // Checkbox 185 $htmlOut .= Xml::element( 'input', 186 array( 187 'type' => 'hidden', 188 'name' => 'ns' . $i, 189 'value' => 1, 190 'id' => 'mw-inputbox-ns' . $i . $idRandStr 191 ) + $checked 192 ); 193 } else { 194 // Checkbox 195 $htmlOut .= ' <div class="inputbox-element">'; 196 $htmlOut .= Xml::element( 'input', 197 array( 198 'type' => 'checkbox', 199 'name' => 'ns' . $i, 200 'value' => 1, 201 'id' => 'mw-inputbox-ns' . $i . $idRandStr 202 ) + $checked 203 ); 204 // Label 205 $htmlOut .= ' ' . Xml::label( $name, 'mw-inputbox-ns' . $i . $idRandStr ); 206 $htmlOut .= '</div> '; 207 } 208 } 209 210 // Line break 211 $htmlOut .= $this->mBR; 212 } elseif ( $type == 'search' ) { 213 // Go button 214 $htmlOut .= Xml::element( 'input', 215 array( 216 'type' => 'submit', 217 'name' => 'go', 218 'class' => 'searchboxGoButton', 219 'value' => $this->mButtonLabel 220 ) 221 ); 222 $htmlOut .= ' '; 223 } 224 225 // Search button 226 $htmlOut .= Xml::element( 'input', 227 array( 228 'type' => 'submit', 229 'name' => 'fulltext', 230 'class' => 'searchboxSearchButton', 231 'value' => $this->mSearchButtonLabel 232 ) 233 ); 234 235 // Hidden fulltext param for IE (bug 17161) 236 if ( $type == 'fulltext' ) { 237 $htmlOut .= Html::hidden( 'fulltext', 'Search' ); 238 } 239 240 $htmlOut .= Xml::closeElement( 'form' ); 241 $htmlOut .= Xml::closeElement( 'div' ); 242 243 // Return HTML 244 return $htmlOut; 245 } 246 247 /** 248 * Generate search form version 2 249 */ 250 public function getSearchForm2() { 251 // Use button label fallbacks 252 if ( !$this->mButtonLabel ) { 253 $this->mButtonLabel = wfMessage( 'inputbox-tryexact' )->text(); 254 } 255 256 if ( $this->mID !== '' ) { 257 $unescapedID = $this->mID; 258 } else { 259 // The label element needs a unique id, use 260 // random number to avoid multiple input boxes 261 // having conflicts. 262 $unescapedID = wfRandom(); 263 } 264 $id = Sanitizer::escapeId( $unescapedID, 'noninitial' ); 265 $htmlLabel = ''; 266 if ( isset( $this->mLabelText ) && strlen( trim( $this->mLabelText ) ) ) { 267 $this->mLabelText = $this->mParser->recursiveTagParse( $this->mLabelText ); 268 $htmlLabel = Xml::openElement( 'label', array( 'for' => 'bodySearchInput' . $id ) ); 269 $htmlLabel .= $this->mLabelText; 270 $htmlLabel .= Xml::closeElement( 'label' ); 271 } 272 $htmlOut = Xml::openElement( 'form', 273 array( 274 'name' => 'bodySearch' . $id, 275 'id' => 'bodySearch' . $id, 276 'class' => 'bodySearch' . ( $this->mInline ? ' mw-inputbox-inline' : '' ), 277 'action' => SpecialPage::getTitleFor( 'Search' )->getLocalUrl(), 278 ) 279 ); 280 $htmlOut .= Xml::openElement( 'div', 281 array( 282 'class' => 'bodySearchWrap' . ( $this->mInline ? ' mw-inputbox-inline' : '' ), 283 'style' => $this->bgColorStyle(), 284 ) 285 ); 286 $htmlOut .= $htmlLabel; 287 $htmlOut .= Xml::element( 'input', 288 array( 289 'type' => $this->mHidden ? 'hidden' : 'text', 290 'name' => 'search', 291 'size' => $this->mWidth, 292 'id' => 'bodySearchInput' . $id, 293 'dir' => $this->mDir, 294 ) 295 ); 296 $htmlOut .= Xml::element( 'input', 297 array( 298 'type' => 'submit', 299 'name' => 'go', 300 'value' => $this->mButtonLabel, 301 'class' => 'bodySearchBtnGo', 302 ) 303 ); 304 305 // Better testing needed here! 306 if ( !empty( $this->mFullTextButton ) ) { 307 $htmlOut .= Xml::element( 'input', 308 array( 309 'type' => 'submit', 310 'name' => 'fulltext', 311 'class' => 'bodySearchBtnSearch', 312 'value' => $this->mSearchButtonLabel 313 ) 314 ); 315 } 316 317 $htmlOut .= Xml::closeElement( 'div' ); 318 $htmlOut .= Xml::closeElement( 'form' ); 319 320 // Return HTML 321 return $htmlOut; 322 } 323 324 /** 325 * Generate create page form 326 */ 327 public function getCreateForm() { 328 global $wgScript; 329 330 if ( $this->mType == "comment" ) { 331 if ( !$this->mButtonLabel ) { 332 $this->mButtonLabel = wfMessage( 'inputbox-postcomment' )->text(); 333 } 334 } else { 335 if ( !$this->mButtonLabel ) { 336 $this->mButtonLabel = wfMessage( 'inputbox-createarticle' )->text(); 337 } 338 } 339 340 $htmlOut = Xml::openElement( 'div', 341 array( 342 'class' => 'mw-inputbox-centered', 343 'style' => $this->bgColorStyle(), 344 ) 345 ); 346 $createBoxParams = array( 347 'name' => 'createbox', 348 'class' => 'createbox', 349 'action' => $wgScript, 350 'method' => 'get' 351 ); 352 if ( $this->mID !== '' ) { 353 $createBoxParams['id'] = Sanitizer::escapeId( $this->mID ); 354 } 355 $htmlOut .= Xml::openElement( 'form', $createBoxParams ); 356 $htmlOut .= Xml::openElement( 'input', 357 array( 358 'type' => 'hidden', 359 'name' => 'action', 360 'value' => 'edit', 361 ) 362 ); 363 $htmlOut .= Xml::openElement( 'input', 364 array( 365 'type' => 'hidden', 366 'name' => 'preload', 367 'value' => $this->mPreload, 368 ) 369 ); 370 $htmlOut .= Xml::openElement( 'input', 371 array( 372 'type' => 'hidden', 373 'name' => 'editintro', 374 'value' => $this->mEditIntro, 375 ) 376 ); 377 $htmlOut .= Xml::openElement( 'input', 378 array( 379 'type' => 'hidden', 380 'name' => 'summary', 381 'value' => $this->mSummary, 382 ) 383 ); 384 $htmlOut .= Xml::openElement( 'input', 385 array( 386 'type' => 'hidden', 387 'name' => 'nosummary', 388 'value' => $this->mNosummary, 389 ) 390 ); 391 $htmlOut .= Xml::openElement( 'input', 392 array( 393 'type' => 'hidden', 394 'name' => 'prefix', 395 'value' => $this->mPrefix, 396 ) 397 ); 398 $htmlOut .= Xml::openElement( 'input', 399 array( 400 'type' => 'hidden', 401 'name' => 'minor', 402 'value' => $this->mMinor, 403 ) 404 ); 405 if ( $this->mType == 'comment' ) { 406 $htmlOut .= Xml::openElement( 'input', 407 array( 408 'type' => 'hidden', 409 'name' => 'section', 410 'value' => 'new', 411 ) 412 ); 413 } 414 $htmlOut .= Xml::openElement( 'input', 415 array( 416 'type' => $this->mHidden ? 'hidden' : 'text', 417 'name' => 'title', 418 'class' => 'createboxInput', 419 'value' => $this->mDefaultText, 420 'placeholder' => $this->mPlaceholderText, 421 'size' => $this->mWidth, 422 'dir' => $this->mDir, 423 ) 424 ); 425 $htmlOut .= $this->mBR; 426 $htmlOut .= Xml::openElement( 'input', 427 array( 428 'type' => 'submit', 429 'name' => 'create', 430 'class' => 'createboxButton', 431 'value' => $this->mButtonLabel 432 ) 433 ); 434 $htmlOut .= Xml::closeElement( 'form' ); 435 $htmlOut .= Xml::closeElement( 'div' ); 436 437 // Return HTML 438 return $htmlOut; 439 } 440 441 /** 442 * Generate move page form 443 */ 444 public function getMoveForm() { 445 global $wgScript; 446 447 if ( !$this->mButtonLabel ) { 448 $this->mButtonLabel = wfMessage( 'inputbox-movearticle' )->text(); 449 } 450 451 $htmlOut = Xml::openElement( 'div', 452 array( 453 'class' => 'mw-inputbox-centered', 454 'style' => $this->bgColorStyle(), 455 ) 456 ); 457 $moveBoxParams = array( 458 'name' => 'movebox', 459 'class' => 'mw-movebox', 460 'action' => $wgScript, 461 'method' => 'get' 462 ); 463 if ( $this->mID !== '' ) { 464 $moveBoxParams['id'] = Sanitizer::escapeId( $this->mID ); 465 } 466 $htmlOut .= Xml::openElement( 'form', $moveBoxParams ); 467 $htmlOut .= Xml::openElement( 'input', 468 array( 469 'type' => 'hidden', 470 'name' => 'title', 471 'value' => SpecialPage::getTitleFor( 'Movepage', $this->mPage )->getPrefixedText(), 472 ) 473 ); 474 $htmlOut .= Xml::openElement( 'input', 475 array( 476 'type' => 'hidden', 477 'name' => 'wpReason', 478 'value' => $this->mSummary, 479 ) 480 ); 481 $htmlOut .= Xml::openElement( 'input', 482 array( 483 'type' => 'hidden', 484 'name' => 'prefix', 485 'value' => $this->mPrefix, 486 ) 487 ); 488 $htmlOut .= Xml::openElement( 'input', 489 array( 490 'type' => $this->mHidden ? 'hidden' : 'text', 491 'name' => 'wpNewTitle', 492 'class' => 'mw-moveboxInput', 493 'value' => $this->mDefaultText, 494 'placeholder' => $this->mPlaceholderText, 495 'size' => $this->mWidth, 496 'dir' => $this->mDir, 497 ) 498 ); 499 $htmlOut .= $this->mBR; 500 $htmlOut .= Xml::openElement( 'input', 501 array( 502 'type' => 'submit', 503 'class' => 'mw-moveboxButton', 504 'value' => $this->mButtonLabel 505 ) 506 ); 507 $htmlOut .= Xml::closeElement( 'form' ); 508 $htmlOut .= Xml::closeElement( 'div' ); 509 510 // Return HTML 511 return $htmlOut; 512 } 513 514 /** 515 * Generate new section form 516 */ 517 public function getCommentForm() { 518 global $wgScript; 519 520 if ( !$this->mButtonLabel ) { 521 $this->mButtonLabel = wfMessage( 'inputbox-postcommenttitle' )->text(); 522 } 523 524 $htmlOut = Xml::openElement( 'div', 525 array( 526 'class' => 'mw-inputbox-centered', 527 'style' => $this->bgColorStyle(), 528 ) 529 ); 530 $commentFormParams = array( 531 'name' => 'commentbox', 532 'class' => 'commentbox', 533 'action' => $wgScript, 534 'method' => 'get' 535 ); 536 if ( $this->mID !== '' ) { 537 $commentFormParams['id'] = Sanitizer::escapeId( $this->mID ); 538 } 539 $htmlOut .= Xml::openElement( 'form', $commentFormParams ); 540 $htmlOut .= Xml::openElement( 'input', 541 array( 542 'type' => 'hidden', 543 'name' => 'action', 544 'value' => 'edit', 545 ) 546 ); 547 $htmlOut .= Xml::openElement( 'input', 548 array( 549 'type' => 'hidden', 550 'name' => 'preload', 551 'value' => $this->mPreload, 552 ) 553 ); 554 $htmlOut .= Xml::openElement( 'input', 555 array( 556 'type' => 'hidden', 557 'name' => 'editintro', 558 'value' => $this->mEditIntro, 559 ) 560 ); 561 $htmlOut .= Xml::openElement( 'input', 562 array( 563 'type' => $this->mHidden ? 'hidden' : 'text', 564 'name' => 'preloadtitle', 565 'class' => 'commentboxInput', 566 'value' => $this->mDefaultText, 567 'placeholder' => $this->mPlaceholderText, 568 'size' => $this->mWidth, 569 'dir' => $this->mDir, 570 ) 571 ); 572 $htmlOut .= Xml::openElement( 'input', 573 array( 574 'type' => 'hidden', 575 'name' => 'section', 576 'value' => 'new', 577 ) 578 ); 579 $htmlOut .= Xml::openElement( 'input', 580 array( 581 'type' => 'hidden', 582 'name' => 'title', 583 'value' => $this->mPage 584 ) 585 ); 586 $htmlOut .= $this->mBR; 587 $htmlOut .= Xml::openElement( 'input', 588 array( 589 'type' => 'submit', 590 'name' => 'create', 591 'class' => 'commentboxButton', 592 'value' => $this->mButtonLabel 593 ) 594 ); 595 $htmlOut .= Xml::closeElement( 'form' ); 596 $htmlOut .= Xml::closeElement( 'div' ); 597 598 // Return HTML 599 return $htmlOut; 600 } 601 602 /** 603 * Extract options from a blob of text 604 * 605 * @param string $text Tag contents 606 */ 607 public function extractOptions( $text ) { 608 wfProfileIn( __METHOD__ ); 609 610 // Parse all possible options 611 $values = array(); 612 foreach ( explode( "\n", $text ) as $line ) { 613 if ( strpos( $line, '=' ) === false ) 614 continue; 615 list( $name, $value ) = explode( '=', $line, 2 ); 616 $values[ strtolower( trim( $name ) ) ] = Sanitizer::decodeCharReferences( trim( $value ) ); 617 } 618 619 // Validate the dir value. 620 if ( isset( $values['dir'] ) && !in_array( $values['dir'], array( 'ltr', 'rtl' ) ) ) { 621 unset( $values['dir'] ); 622 } 623 624 // Build list of options, with local member names 625 $options = array( 626 'type' => 'mType', 627 'width' => 'mWidth', 628 'preload' => 'mPreload', 629 'page' => 'mPage', 630 'editintro' => 'mEditIntro', 631 'summary' => 'mSummary', 632 'nosummary' => 'mNosummary', 633 'minor' => 'mMinor', 634 'break' => 'mBR', 635 'default' => 'mDefaultText', 636 'placeholder' => 'mPlaceholderText', 637 'bgcolor' => 'mBGColor', 638 'buttonlabel' => 'mButtonLabel', 639 'searchbuttonlabel' => 'mSearchButtonLabel', 640 'fulltextbutton' => 'mFullTextButton', 641 'namespaces' => 'mNamespaces', 642 'labeltext' => 'mLabelText', 643 'hidden' => 'mHidden', 644 'id' => 'mID', 645 'inline' => 'mInline', 646 'prefix' => 'mPrefix', 647 'dir' => 'mDir', 648 ); 649 foreach ( $options as $name => $var ) { 650 if ( isset( $values[$name] ) ) { 651 $this->$var = $values[$name]; 652 } 653 } 654 655 // Insert a line break if configured to do so 656 $this->mBR = ( strtolower( $this->mBR ) == "no" ) ? ' ' : '<br />'; 657 658 // Validate the width; make sure it's a valid, positive integer 659 $this->mWidth = intval( $this->mWidth <= 0 ? 50 : $this->mWidth ); 660 661 // Validate background color 662 if ( !$this->isValidColor( $this->mBGColor ) ) { 663 $this->mBGColor = 'transparent'; 664 } 665 wfProfileOut( __METHOD__ ); 666 } 667 668 /** 669 * Do a security check on the bgcolor parameter 670 */ 671 public function isValidColor( $color ) { 672 $regex = <<<REGEX 673 /^ ( 674 [a-zA-Z]* | # color names 675 \# [0-9a-f]{3} | # short hexadecimal 676 \# [0-9a-f]{6} | # long hexadecimal 677 rgb \s* \( \s* ( 678 \d+ \s* , \s* \d+ \s* , \s* \d+ | # rgb integer 679 [0-9.]+% \s* , \s* [0-9.]+% \s* , \s* [0-9.]+% # rgb percent 680 ) \s* \) 681 ) $ /xi 682 REGEX; 683 return (bool) preg_match( $regex, $color ); 684 } 685 686 private function bgColorStyle() { 687 if ( $this->mBGColor != 'transparent' ) { 688 return 'background-color: ' . $this->mBGColor . ';'; 689 } 690 return ''; 691 } 692 }
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 |