[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Cologne Blue: A nicer-looking alternative to Standard. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 * http://www.gnu.org/copyleft/gpl.html 19 * 20 * @todo document 21 * @file 22 * @ingroup Skins 23 */ 24 25 if ( !defined( 'MEDIAWIKI' ) ) { 26 die( -1 ); 27 } 28 29 /** 30 * @todo document 31 * @ingroup Skins 32 */ 33 class SkinCologneBlue extends SkinTemplate { 34 public $skinname = 'cologneblue'; 35 public $template = 'CologneBlueTemplate'; 36 37 /** 38 * @param OutputPage $out 39 */ 40 function setupSkinUserCss( OutputPage $out ) { 41 parent::setupSkinUserCss( $out ); 42 $out->addModuleStyles( 'mediawiki.legacy.oldshared' ); 43 $out->addModuleStyles( 'skins.cologneblue' ); 44 } 45 46 /** 47 * Override langlink formatting behavior not to uppercase the language names. 48 * See otherLanguages() in CologneBlueTemplate. 49 * @param string $name 50 * @return string 51 */ 52 function formatLanguageName( $name ) { 53 return $name; 54 } 55 } 56 57 class CologneBlueTemplate extends BaseTemplate { 58 function execute() { 59 // Suppress warnings to prevent notices about missing indexes in $this->data 60 wfSuppressWarnings(); 61 $this->html( 'headelement' ); 62 echo $this->beforeContent(); 63 $this->html( 'bodytext' ); 64 echo "\n"; 65 echo $this->afterContent(); 66 $this->html( 'dataAfterContent' ); 67 $this->printTrail(); 68 echo "\n</body></html>"; 69 wfRestoreWarnings(); 70 } 71 72 /** 73 * Language/charset variant links for classic-style skins 74 * @return string 75 */ 76 function variantLinks() { 77 $s = array(); 78 79 $variants = $this->data['content_navigation']['variants']; 80 81 foreach ( $variants as $key => $link ) { 82 $s[] = $this->makeListItem( $key, $link, array( 'tag' => 'span' ) ); 83 } 84 85 return $this->getSkin()->getLanguage()->pipeList( $s ); 86 } 87 88 function otherLanguages() { 89 if ( $this->config->get( 'HideInterlanguageLinks' ) ) { 90 return ""; 91 } 92 93 $html = ''; 94 95 // We override SkinTemplate->formatLanguageName() in SkinCologneBlue 96 // not to capitalize the language names. 97 $language_urls = $this->data['language_urls']; 98 if ( !empty( $language_urls ) ) { 99 $s = array(); 100 foreach ( $language_urls as $key => $data ) { 101 $s[] = $this->makeListItem( $key, $data, array( 'tag' => 'span' ) ); 102 } 103 104 $html = wfMessage( 'otherlanguages' )->text() 105 . wfMessage( 'colon-separator' )->text() 106 . $this->getSkin()->getLanguage()->pipeList( $s ); 107 } 108 109 $html .= $this->renderAfterPortlet( 'lang' ); 110 111 return $html; 112 } 113 114 /** 115 * @param string $name 116 */ 117 protected function renderAfterPortlet( $name ) { 118 $content = ''; 119 wfRunHooks( 'BaseTemplateAfterPortlet', array( $this, $name, &$content ) ); 120 121 $html = $content !== '' ? "<div class='after-portlet after-portlet-$name'>$content</div>" : ''; 122 123 return $html; 124 } 125 126 function pageTitleLinks() { 127 $s = array(); 128 $footlinks = $this->getFooterLinks(); 129 130 foreach ( $footlinks['places'] as $item ) { 131 $s[] = $this->data[$item]; 132 } 133 134 return $this->getSkin()->getLanguage()->pipeList( $s ); 135 } 136 137 /** 138 * Used in bottomLinks() to eliminate repetitive code. 139 * 140 * @param string $key Key to be passed to makeListItem() 141 * @param array $navlink Navlink suitable for processNavlinkForDocument() 142 * @param string $message Key of the message to use in place of standard text 143 * 144 * @return string 145 */ 146 function processBottomLink( $key, $navlink, $message = null ) { 147 if ( !$navlink ) { 148 // Empty navlinks might be passed. 149 return null; 150 } 151 152 if ( $message ) { 153 $navlink['text'] = wfMessage( $message )->escaped(); 154 } 155 156 return $this->makeListItem( 157 $key, 158 $this->processNavlinkForDocument( $navlink ), 159 array( 'tag' => 'span' ) 160 ); 161 } 162 163 function bottomLinks() { 164 $toolbox = $this->getToolbox(); 165 $content_nav = $this->data['content_navigation']; 166 167 $lines = array(); 168 169 if ( $this->getSkin()->getOutput()->isArticleRelated() ) { 170 // First row. Regular actions. 171 $element = array(); 172 173 $editLinkMessage = $this->getSkin()->getTitle()->exists() ? 'editthispage' : 'create-this-page'; 174 $element[] = $this->processBottomLink( 'edit', $content_nav['views']['edit'], $editLinkMessage ); 175 $element[] = $this->processBottomLink( 176 'viewsource', 177 $content_nav['views']['viewsource'], 178 'viewsource' 179 ); 180 181 $element[] = $this->processBottomLink( 182 'watch', 183 $content_nav['actions']['watch'], 184 'watchthispage' 185 ); 186 $element[] = $this->processBottomLink( 187 'unwatch', 188 $content_nav['actions']['unwatch'], 189 'unwatchthispage' 190 ); 191 192 $element[] = $this->talkLink(); 193 194 $element[] = $this->processBottomLink( 'history', $content_nav['views']['history'], 'history' ); 195 $element[] = $this->processBottomLink( 'info', $toolbox['info'] ); 196 $element[] = $this->processBottomLink( 'whatlinkshere', $toolbox['whatlinkshere'] ); 197 $element[] = $this->processBottomLink( 'recentchangeslinked', $toolbox['recentchangeslinked'] ); 198 199 $element[] = $this->processBottomLink( 'contributions', $toolbox['contributions'] ); 200 $element[] = $this->processBottomLink( 'emailuser', $toolbox['emailuser'] ); 201 202 $lines[] = $this->getSkin()->getLanguage()->pipeList( array_filter( $element ) ); 203 204 // Second row. Privileged actions. 205 $element = array(); 206 207 $element[] = $this->processBottomLink( 208 'delete', 209 $content_nav['actions']['delete'], 210 'deletethispage' 211 ); 212 $element[] = $this->processBottomLink( 213 'undelete', 214 $content_nav['actions']['undelete'], 215 'undeletethispage' 216 ); 217 218 $element[] = $this->processBottomLink( 219 'protect', 220 $content_nav['actions']['protect'], 221 'protectthispage' 222 ); 223 $element[] = $this->processBottomLink( 224 'unprotect', 225 $content_nav['actions']['unprotect'], 226 'unprotectthispage' 227 ); 228 229 $element[] = $this->processBottomLink( 'move', $content_nav['actions']['move'], 'movethispage' ); 230 231 $lines[] = $this->getSkin()->getLanguage()->pipeList( array_filter( $element ) ); 232 233 // Third row. Language links. 234 $lines[] = $this->otherLanguages(); 235 } 236 237 return implode( array_filter( $lines ), "<br />\n" ) . "<br />\n"; 238 } 239 240 function talkLink() { 241 $title = $this->getSkin()->getTitle(); 242 243 if ( $title->getNamespace() == NS_SPECIAL ) { 244 // No discussion links for special pages 245 return ""; 246 } 247 248 $companionTitle = $title->isTalkPage() ? $title->getSubjectPage() : $title->getTalkPage(); 249 $companionNamespace = $companionTitle->getNamespace(); 250 251 // TODO these messages are only be used by CologneBlue, 252 // kill and replace with something more sensibly named? 253 $nsToMessage = array( 254 NS_MAIN => 'articlepage', 255 NS_USER => 'userpage', 256 NS_PROJECT => 'projectpage', 257 NS_FILE => 'imagepage', 258 NS_MEDIAWIKI => 'mediawikipage', 259 NS_TEMPLATE => 'templatepage', 260 NS_HELP => 'viewhelppage', 261 NS_CATEGORY => 'categorypage', 262 NS_FILE => 'imagepage', 263 ); 264 265 // Find out the message to use for link text. Use either the array above or, 266 // for non-talk pages, a generic "discuss this" message. 267 // Default is the same as for main namespace. 268 if ( isset( $nsToMessage[$companionNamespace] ) ) { 269 $message = $nsToMessage[$companionNamespace]; 270 } else { 271 $message = $companionTitle->isTalkPage() ? 'talkpage' : 'articlepage'; 272 } 273 274 // Obviously this can't be reasonable and just return the key for talk 275 // namespace, only for content ones. Thus we have to mangle it in 276 // exactly the same way SkinTemplate does. (bug 40805) 277 $key = $companionTitle->getNamespaceKey( '' ); 278 if ( $companionTitle->isTalkPage() ) { 279 $key = ( $key == 'main' ? 'talk' : $key . "_talk" ); 280 } 281 282 // Use the regular navigational link, but replace its text. Everything else stays unmodified. 283 $namespacesLinks = $this->data['content_navigation']['namespaces']; 284 285 return $this->processBottomLink( $message, $namespacesLinks[$key], $message ); 286 } 287 288 /** 289 * Takes a navigational link generated by SkinTemplate in whichever way 290 * and mangles attributes unsuitable for repeated use. In particular, this 291 * modifies the ids and removes the accesskeys. This is necessary to be 292 * able to use the same navlink twice, e.g. in sidebar and in footer. 293 * 294 * @param array $navlink Navigational link generated by SkinTemplate 295 * @param mixed $idPrefix Prefix to add to id of this navlink. If false, id 296 * is removed entirely. Default is 'cb-'. 297 */ 298 function processNavlinkForDocument( $navlink, $idPrefix = 'cb-' ) { 299 if ( $navlink['id'] ) { 300 $navlink['single-id'] = $navlink['id']; // to allow for tooltip generation 301 $navlink['tooltiponly'] = true; // but no accesskeys 302 303 // mangle or remove the id 304 if ( $idPrefix === false ) { 305 unset( $navlink['id'] ); 306 } else { 307 $navlink['id'] = $idPrefix . $navlink['id']; 308 } 309 } 310 311 return $navlink; 312 } 313 314 /** 315 * @return string 316 */ 317 function beforeContent() { 318 ob_start(); 319 ?> 320 <div id="content"> 321 <div id="topbar"> 322 <p id="sitetitle" role="banner"> 323 <a href="<?php echo htmlspecialchars( $this->data['nav_urls']['mainpage']['href'] ) ?>"> 324 <?php echo wfMessage( 'sitetitle' )->escaped() ?> 325 </a> 326 </p> 327 328 <p id="sitesub"><?php echo wfMessage( 'sitesubtitle' )->escaped() ?></p> 329 330 <div id="linkcollection" role="navigation"> 331 <div id="langlinks"><?php echo str_replace( '<br />', '', $this->otherLanguages() ) ?></div> 332 <?php echo $this->getSkin()->getCategories() ?> 333 <div id="titlelinks"><?php echo $this->pageTitleLinks() ?></div> 334 <?php 335 if ( $this->data['newtalk'] ) { 336 ?> 337 <div class="usermessage"><strong><?php echo $this->data['newtalk'] ?></strong></div> 338 <?php 339 } 340 ?> 341 </div> 342 </div> 343 <div id="article" class="mw-body" role="main"> 344 <?php 345 if ( $this->getSkin()->getSiteNotice() ) { 346 ?> 347 <div id="siteNotice"><?php echo $this->getSkin()->getSiteNotice() ?></div> 348 <?php 349 } 350 ?> 351 <h1 id="firstHeading" lang="<?php 352 $this->data['pageLanguage'] = $this->getSkin()->getTitle()->getPageViewLanguage()->getHtmlCode(); 353 $this->text( 'pageLanguage' ); 354 ?>"><span dir="auto"><?php echo $this->data['title'] ?></span></h1> 355 <?php 356 if ( $this->translator->translate( 'tagline' ) ) { 357 ?> 358 <p class="tagline"><?php 359 echo htmlspecialchars( $this->translator->translate( 'tagline' ) ) 360 ?></p> 361 <?php 362 } 363 ?> 364 <?php 365 if ( $this->getSkin()->getOutput()->getSubtitle() ) { 366 ?> 367 <p class="subtitle"><?php echo $this->getSkin()->getOutput()->getSubtitle() ?></p> 368 <?php 369 } 370 ?> 371 <?php 372 if ( $this->getSkin()->subPageSubtitle() ) { 373 ?> 374 <p class="subpages"><?php echo $this->getSkin()->subPageSubtitle() ?></p> 375 <?php 376 } 377 ?> 378 <?php 379 $s = ob_get_contents(); 380 ob_end_clean(); 381 382 return $s; 383 } 384 385 /** 386 * @return string 387 */ 388 function afterContent() { 389 ob_start(); 390 ?> 391 </div> 392 <div id="footer"> 393 <div id="footer-navigation" role="navigation"> 394 <?php 395 // Page-related links 396 echo $this->bottomLinks(); 397 echo "\n<br />"; 398 399 // Footer and second searchbox 400 echo $this->getSkin()->getLanguage()->pipeList( array( 401 $this->getSkin()->mainPageLink(), 402 $this->getSkin()->aboutLink(), 403 $this->searchForm( 'footer' ) 404 ) ); 405 ?> 406 </div> 407 <div id="footer-info" role="contentinfo"> 408 <?php 409 // Standard footer info 410 $footlinks = $this->getFooterLinks(); 411 if ( $footlinks['info'] ) { 412 foreach ( $footlinks['info'] as $item ) { 413 echo $this->data[$item] . ' '; 414 } 415 } 416 ?> 417 </div> 418 </div> 419 </div> 420 <div id="mw-navigation"> 421 <h2><?php echo wfMessage( 'navigation-heading' )->escaped() ?></h2> 422 423 <div id="toplinks" role="navigation"> 424 <p id="syslinks"><?php echo $this->sysLinks() ?></p> 425 426 <p id="variantlinks"><?php echo $this->variantLinks() ?></p> 427 </div> 428 <?php echo $this->quickBar() ?> 429 </div> 430 <?php 431 $s = ob_get_contents(); 432 ob_end_clean(); 433 434 return $s; 435 } 436 437 /** 438 * @return string 439 */ 440 function sysLinks() { 441 $s = array( 442 $this->getSkin()->mainPageLink(), 443 Linker::linkKnown( 444 Title::newFromText( wfMessage( 'aboutpage' )->inContentLanguage()->text() ), 445 wfMessage( 'about' )->text() 446 ), 447 Linker::makeExternalLink( 448 Skin::makeInternalOrExternalUrl( wfMessage( 'helppage' )->inContentLanguage()->text() ), 449 wfMessage( 'help' )->text(), 450 false 451 ), 452 Linker::linkKnown( 453 Title::newFromText( wfMessage( 'faqpage' )->inContentLanguage()->text() ), 454 wfMessage( 'faq' )->text() 455 ), 456 ); 457 458 $personalUrls = $this->getPersonalTools(); 459 foreach ( array( 'logout', 'createaccount', 'login' ) as $key ) { 460 if ( $personalUrls[$key] ) { 461 $s[] = $this->makeListItem( $key, $personalUrls[$key], array( 'tag' => 'span' ) ); 462 } 463 } 464 465 return $this->getSkin()->getLanguage()->pipeList( $s ); 466 } 467 468 /** 469 * Adds CologneBlue-specific items to the sidebar: qbedit, qbpageoptions and qbmyoptions menus. 470 * 471 * @param array $bar Sidebar data 472 * @return array Modified sidebar data 473 */ 474 function sidebarAdditions( $bar ) { 475 // "This page" and "Edit" menus 476 // We need to do some massaging here... we reuse all of the items, 477 // except for $...['views']['view'], as $...['namespaces']['main'] and 478 // $...['namespaces']['talk'] together serve the same purpose. We also 479 // don't use $...['variants'], these are displayed in the top menu. 480 $content_navigation = $this->data['content_navigation']; 481 $qbpageoptions = array_merge( 482 $content_navigation['namespaces'], 483 array( 484 'history' => $content_navigation['views']['history'], 485 'watch' => $content_navigation['actions']['watch'], 486 'unwatch' => $content_navigation['actions']['unwatch'], 487 ) 488 ); 489 $content_navigation['actions']['watch'] = null; 490 $content_navigation['actions']['unwatch'] = null; 491 $qbedit = array_merge( 492 array( 493 'edit' => $content_navigation['views']['edit'], 494 'addsection' => $content_navigation['views']['addsection'], 495 ), 496 $content_navigation['actions'] 497 ); 498 499 // Personal tools ("My pages") 500 $qbmyoptions = $this->getPersonalTools(); 501 foreach ( array( 'logout', 'createaccount', 'login', ) as $key ) { 502 $qbmyoptions[$key] = null; 503 } 504 505 // Use the closest reasonable name 506 $bar['cactions'] = $qbedit; 507 $bar['pageoptions'] = $qbpageoptions; // this is a non-standard portlet name, but nothing fits 508 $bar['personal'] = $qbmyoptions; 509 510 return $bar; 511 } 512 513 /** 514 * Compute the sidebar 515 * @access private 516 * 517 * @return string 518 */ 519 function quickBar() { 520 // Massage the sidebar. We want to: 521 // * place SEARCH at the beginning 522 // * add new portlets before TOOLBOX (or at the end, if it's missing) 523 // * remove LANGUAGES (langlinks are displayed elsewhere) 524 $orig_bar = $this->data['sidebar']; 525 $bar = array(); 526 $hasToolbox = false; 527 528 // Always display search first 529 $bar['SEARCH'] = true; 530 // Copy everything except for langlinks, inserting new items before toolbox 531 foreach ( $orig_bar as $heading => $data ) { 532 if ( $heading == 'TOOLBOX' ) { 533 // Insert the stuff 534 $bar = $this->sidebarAdditions( $bar ); 535 $hasToolbox = true; 536 } 537 538 if ( $heading != 'LANGUAGES' ) { 539 $bar[$heading] = $data; 540 } 541 } 542 // If toolbox is missing, add our items at the end 543 if ( !$hasToolbox ) { 544 $bar = $this->sidebarAdditions( $bar ); 545 } 546 547 // Fill out special sidebar items with content 548 $orig_bar = $bar; 549 $bar = array(); 550 foreach ( $orig_bar as $heading => $data ) { 551 if ( $heading == 'SEARCH' ) { 552 $bar['search'] = $this->searchForm( 'sidebar' ); 553 } elseif ( $heading == 'TOOLBOX' ) { 554 $bar['tb'] = $this->getToolbox(); 555 } else { 556 $bar[$heading] = $data; 557 } 558 } 559 560 // Output the sidebar 561 // CologneBlue uses custom messages for some portlets, but we should keep the ids for consistency 562 $idToMessage = array( 563 'search' => 'qbfind', 564 'navigation' => 'qbbrowse', 565 'tb' => 'toolbox', 566 'cactions' => 'qbedit', 567 'personal' => 'qbmyoptions', 568 'pageoptions' => 'qbpageoptions', 569 ); 570 571 $s = "<div id='quickbar'>\n"; 572 573 foreach ( $bar as $heading => $data ) { 574 $portletId = Sanitizer::escapeId( "p-$heading" ); 575 $headingMsg = wfMessage( $idToMessage[$heading] ? $idToMessage[$heading] : $heading ); 576 $headingHTML = "<h3>"; 577 $headingHTML .= $headingMsg->exists() 578 ? $headingMsg->escaped() 579 : htmlspecialchars( $heading ); 580 $headingHTML .= "</h3>"; 581 $listHTML = ""; 582 583 if ( is_array( $data ) ) { 584 // $data is an array of links 585 foreach ( $data as $key => $link ) { 586 // Can be empty due to how the sidebar additions are done 587 if ( $link ) { 588 $listHTML .= $this->makeListItem( $key, $link ); 589 } 590 } 591 if ( $listHTML ) { 592 $listHTML = "<ul>$listHTML</ul>"; 593 } 594 } else { 595 // $data is a HTML <ul>-list string 596 $listHTML = $data; 597 } 598 599 if ( $listHTML ) { 600 $role = ( $heading == 'search' ) ? 'search' : 'navigation'; 601 $s .= "<div class=\"portlet\" id=\"$portletId\" " 602 . "role=\"$role\">\n$headingHTML\n$listHTML\n</div>\n"; 603 } 604 605 $s .= $this->renderAfterPortlet( $heading ); 606 } 607 608 $s .= "</div>\n"; 609 610 return $s; 611 } 612 613 /** 614 * @param string $label 615 * @return string 616 */ 617 function searchForm( $which ) { 618 $search = $this->getSkin()->getRequest()->getText( 'search' ); 619 $action = $this->data['searchaction']; 620 $s = "<form id=\"searchform-" . htmlspecialchars( $which ) 621 . "\" method=\"get\" class=\"inline\" action=\"$action\">"; 622 if ( $which == 'footer' ) { 623 $s .= wfMessage( 'qbfind' )->text() . ": "; 624 } 625 626 $s .= $this->makeSearchInput( array( 627 'class' => 'mw-searchInput', 628 'type' => 'text', 629 'size' => '14' 630 ) ); 631 $s .= ( $which == 'footer' ? " " : "<br />" ); 632 $s .= $this->makeSearchButton( 'go', array( 'class' => 'searchButton' ) ); 633 634 if ( $this->config->get( 'UseTwoButtonsSearchForm' ) ) { 635 $s .= $this->makeSearchButton( 'fulltext', array( 'class' => 'searchButton' ) ); 636 } else { 637 $s .= '<div><a href="' . $action . '" rel="search">' 638 . wfMessage( 'powersearch-legend' )->escaped() . "</a></div>\n"; 639 } 640 641 $s .= '</form>'; 642 643 return $s; 644 } 645 }
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 |