MediaWiki  REL1_19
SkinTemplate.php
Go to the documentation of this file.
00001 <?php
00023 if ( !defined( 'MEDIAWIKI' ) ) {
00024         die( 1 );
00025 }
00026 
00034 class MediaWiki_I18N {
00035         var $_context = array();
00036 
00037         function set( $varName, $value ) {
00038                 $this->_context[$varName] = $value;
00039         }
00040 
00041         function translate( $value ) {
00042                 wfProfileIn( __METHOD__ );
00043 
00044                 // Hack for i18n:attributes in PHPTAL 1.0.0 dev version as of 2004-10-23
00045                 $value = preg_replace( '/^string:/', '', $value );
00046 
00047                 $value = wfMsg( $value );
00048                 // interpolate variables
00049                 $m = array();
00050                 while( preg_match( '/\$([0-9]*?)/sm', $value, $m ) ) {
00051                         list( $src, $var ) = $m;
00052                         wfSuppressWarnings();
00053                         $varValue = $this->_context[$var];
00054                         wfRestoreWarnings();
00055                         $value = str_replace( $src, $varValue, $value );
00056                 }
00057                 wfProfileOut( __METHOD__ );
00058                 return $value;
00059         }
00060 }
00061 
00074 class SkinTemplate extends Skin {
00083         var $skinname = 'monobook';
00084 
00089         var $stylename = 'monobook';
00090 
00095         var $template = 'QuickTemplate';
00096 
00101         var $useHeadElement = false;
00102 
00110         function setupSkinUserCss( OutputPage $out ) {
00111                 $out->addModuleStyles( array( 'mediawiki.legacy.shared', 'mediawiki.legacy.commonPrint' ) );
00112         }
00113 
00125         function setupTemplate( $classname, $repository = false, $cache_dir = false ) {
00126                 return new $classname();
00127         }
00128 
00134         function outputPage( OutputPage $out=null ) {
00135                 global $wgContLang;
00136                 global $wgScript, $wgStylePath;
00137                 global $wgMimeType, $wgJsMimeType;
00138                 global $wgXhtmlDefaultNamespace, $wgXhtmlNamespaces, $wgHtml5Version;
00139                 global $wgDisableCounters, $wgSitename, $wgLogo, $wgHideInterlanguageLinks;
00140                 global $wgMaxCredits, $wgShowCreditsIfMax;
00141                 global $wgPageShowWatchingUsers;
00142                 global $wgDebugComments;
00143                 global $wgArticlePath, $wgScriptPath, $wgServer;
00144 
00145                 wfProfileIn( __METHOD__ );
00146                 Profiler::instance()->setTemplated( true );
00147 
00148                 $oldContext = null;
00149                 if ( $out !== null ) {
00150                         // @todo Add wfDeprecated in 1.20
00151                         $oldContext = $this->getContext();
00152                         $this->setContext( $out->getContext() );
00153                 }
00154 
00155                 $out = $this->getOutput();
00156                 $request = $this->getRequest();
00157                 $user = $this->getUser();
00158                 $title = $this->getTitle();
00159 
00160                 wfProfileIn( __METHOD__ . '-init' );
00161                 $this->initPage( $out );
00162 
00163                 $tpl = $this->setupTemplate( $this->template, 'skins' );
00164                 wfProfileOut( __METHOD__ . '-init' );
00165 
00166                 wfProfileIn( __METHOD__ . '-stuff' );
00167                 $this->thispage = $title->getPrefixedDBkey();
00168                 $this->titletxt = $title->getPrefixedText();
00169                 $this->userpage = $user->getUserPage()->getPrefixedText();
00170                 $query = array();
00171                 if ( !$request->wasPosted() ) {
00172                         $query = $request->getValues();
00173                         unset( $query['title'] );
00174                         unset( $query['returnto'] );
00175                         unset( $query['returntoquery'] );
00176                 }
00177                 $this->thisquery = wfArrayToCGI( $query );
00178                 $this->loggedin = $user->isLoggedIn();
00179                 $this->username = $user->getName();
00180 
00181                 if ( $this->loggedin || $this->showIPinHeader() ) {
00182                         $this->userpageUrlDetails = self::makeUrlDetails( $this->userpage );
00183                 } else {
00184                         # This won't be used in the standard skins, but we define it to preserve the interface
00185                         # To save time, we check for existence
00186                         $this->userpageUrlDetails = self::makeKnownUrlDetails( $this->userpage );
00187                 }
00188 
00189                 wfProfileOut( __METHOD__ . '-stuff' );
00190 
00191                 wfProfileIn( __METHOD__ . '-stuff-head' );
00192                 if ( !$this->useHeadElement ) {
00193                         $tpl->set( 'pagecss', false );
00194                         $tpl->set( 'usercss', false );
00195 
00196                         $tpl->set( 'userjs', false );
00197                         $tpl->set( 'userjsprev', false );
00198 
00199                         $tpl->set( 'jsvarurl', false );
00200 
00201                         $tpl->setRef( 'xhtmldefaultnamespace', $wgXhtmlDefaultNamespace );
00202                         $tpl->set( 'xhtmlnamespaces', $wgXhtmlNamespaces );
00203                         $tpl->set( 'html5version', $wgHtml5Version );
00204                         $tpl->set( 'headlinks', $out->getHeadLinks() );
00205                         $tpl->set( 'csslinks', $out->buildCssLinks() );
00206                         $tpl->set( 'pageclass', $this->getPageClasses( $title ) );
00207                         $tpl->set( 'skinnameclass', ( 'skin-' . Sanitizer::escapeClass( $this->getSkinName() ) ) );
00208                 }
00209                 wfProfileOut( __METHOD__ . '-stuff-head' );
00210 
00211                 wfProfileIn( __METHOD__ . '-stuff2' );
00212                 $tpl->set( 'title', $out->getPageTitle() );
00213                 $tpl->set( 'pagetitle', $out->getHTMLTitle() );
00214                 $tpl->set( 'displaytitle', $out->mPageLinkTitle );
00215 
00216                 $tpl->setRef( 'thispage', $this->thispage );
00217                 $tpl->setRef( 'titleprefixeddbkey', $this->thispage );
00218                 $tpl->set( 'titletext', $title->getText() );
00219                 $tpl->set( 'articleid', $title->getArticleId() );
00220 
00221                 $tpl->set( 'isarticle', $out->isArticle() );
00222 
00223                 $subpagestr = $this->subPageSubtitle();
00224                 if ( $subpagestr !== '' ) {
00225                         $subpagestr = '<span class="subpages">' . $subpagestr . '</span>';
00226                 }
00227                 $tpl->set( 'subtitle',  $subpagestr . $out->getSubtitle() );
00228 
00229                 $undelete = $this->getUndeleteLink();
00230                 if ( $undelete === '' ) {
00231                         $tpl->set( 'undelete', '' );
00232                 } else {
00233                         $tpl->set( 'undelete', '<span class="subpages">' . $undelete . '</span>' );
00234                 }
00235 
00236                 $tpl->set( 'catlinks', $this->getCategories() );
00237                 if( $out->isSyndicated() ) {
00238                         $feeds = array();
00239                         foreach( $out->getSyndicationLinks() as $format => $link ) {
00240                                 $feeds[$format] = array(
00241                                         'text' => $this->msg( "feed-$format" )->text(),
00242                                         'href' => $link
00243                                 );
00244                         }
00245                         $tpl->setRef( 'feeds', $feeds );
00246                 } else {
00247                         $tpl->set( 'feeds', false );
00248                 }
00249 
00250                 $tpl->setRef( 'mimetype', $wgMimeType );
00251                 $tpl->setRef( 'jsmimetype', $wgJsMimeType );
00252                 $tpl->set( 'charset', 'UTF-8' );
00253                 $tpl->setRef( 'wgScript', $wgScript );
00254                 $tpl->setRef( 'skinname', $this->skinname );
00255                 $tpl->set( 'skinclass', get_class( $this ) );
00256                 $tpl->setRef( 'skin', $this );
00257                 $tpl->setRef( 'stylename', $this->stylename );
00258                 $tpl->set( 'printable', $out->isPrintable() );
00259                 $tpl->set( 'handheld', $request->getBool( 'handheld' ) );
00260                 $tpl->setRef( 'loggedin', $this->loggedin );
00261                 $tpl->set( 'notspecialpage', !$title->isSpecialPage() );
00262                 /* XXX currently unused, might get useful later
00263                 $tpl->set( 'editable', ( !$title->isSpecialPage() ) );
00264                 $tpl->set( 'exists', $title->getArticleID() != 0 );
00265                 $tpl->set( 'watch', $title->userIsWatching() ? 'unwatch' : 'watch' );
00266                 $tpl->set( 'protect', count( $title->isProtected() ) ? 'unprotect' : 'protect' );
00267                 $tpl->set( 'helppage', $this->msg( 'helppage' )->text() );
00268                 */
00269                 $tpl->set( 'searchaction', $this->escapeSearchLink() );
00270                 $tpl->set( 'searchtitle', SpecialPage::getTitleFor( 'Search' )->getPrefixedDBKey() );
00271                 $tpl->set( 'search', trim( $request->getVal( 'search' ) ) );
00272                 $tpl->setRef( 'stylepath', $wgStylePath );
00273                 $tpl->setRef( 'articlepath', $wgArticlePath );
00274                 $tpl->setRef( 'scriptpath', $wgScriptPath );
00275                 $tpl->setRef( 'serverurl', $wgServer );
00276                 $tpl->setRef( 'logopath', $wgLogo );
00277                 $tpl->setRef( 'sitename', $wgSitename );
00278 
00279                 $lang = $this->getLanguage();
00280                 $userlang = $lang->getHtmlCode();
00281                 $userdir  = $lang->getDir();
00282 
00283                 $tpl->set( 'lang', $userlang );
00284                 $tpl->set( 'dir', $userdir );
00285                 $tpl->set( 'rtl', $lang->isRTL() );
00286 
00287                 $tpl->set( 'capitalizeallnouns', $lang->capitalizeAllNouns() ? ' capitalize-all-nouns' : '' );
00288                 $tpl->set( 'showjumplinks', $user->getOption( 'showjumplinks' ) );
00289                 $tpl->set( 'username', $this->loggedin ? $this->username : null );
00290                 $tpl->setRef( 'userpage', $this->userpage );
00291                 $tpl->setRef( 'userpageurl', $this->userpageUrlDetails['href'] );
00292                 $tpl->set( 'userlang', $userlang );
00293 
00294                 // Users can have their language set differently than the
00295                 // content of the wiki. For these users, tell the web browser
00296                 // that interface elements are in a different language.
00297                 $tpl->set( 'userlangattributes', '' );
00298                 $tpl->set( 'specialpageattributes', '' ); # obsolete
00299 
00300                 if ( $userlang !== $wgContLang->getHtmlCode() || $userdir !== $wgContLang->getDir() ) {
00301                         $escUserlang = htmlspecialchars( $userlang );
00302                         $escUserdir = htmlspecialchars( $userdir );
00303                         // Attributes must be in double quotes because htmlspecialchars() doesn't
00304                         // escape single quotes
00305                         $attrs = " lang=\"$escUserlang\" dir=\"$escUserdir\"";
00306                         $tpl->set( 'userlangattributes', $attrs );
00307                 }
00308 
00309                 wfProfileOut( __METHOD__ . '-stuff2' );
00310 
00311                 wfProfileIn( __METHOD__ . '-stuff3' );
00312                 $tpl->set( 'newtalk', $this->getNewtalks() );
00313                 $tpl->set( 'logo', $this->logoText() );
00314 
00315                 $tpl->set( 'copyright', false );
00316                 $tpl->set( 'viewcount', false );
00317                 $tpl->set( 'lastmod', false );
00318                 $tpl->set( 'credits', false );
00319                 $tpl->set( 'numberofwatchingusers', false );
00320                 if ( $out->isArticle() && $title->exists() ) {
00321                         if ( $this->isRevisionCurrent() ) {
00322                                 if ( !$wgDisableCounters ) {
00323                                         $viewcount = $this->getWikiPage()->getCount();
00324                                         if ( $viewcount ) {
00325                                                 $tpl->set( 'viewcount', $this->msg( 'viewcount' )->numParams( $viewcount )->parse() );
00326                                         }
00327                                 }
00328 
00329                                 if( $wgPageShowWatchingUsers ) {
00330                                         $dbr = wfGetDB( DB_SLAVE );
00331                                         $num = $dbr->selectField( 'watchlist', 'COUNT(*)',
00332                                                 array( 'wl_title' => $title->getDBkey(), 'wl_namespace' => $title->getNamespace() ),
00333                                                 __METHOD__
00334                                         );
00335                                         if( $num > 0 ) {
00336                                                 $tpl->set( 'numberofwatchingusers',
00337                                                         $this->msg( 'number_of_watching_users_pageview' )->numParams( $num )->parse()
00338                                                 );
00339                                         }
00340                                 }
00341 
00342                                 if ( $wgMaxCredits != 0 ) {
00343                                         $tpl->set( 'credits', Action::factory( 'credits', $this->getWikiPage(),
00344                                                 $this->getContext() )->getCredits( $wgMaxCredits, $wgShowCreditsIfMax ) );
00345                                 } else {
00346                                         $tpl->set( 'lastmod', $this->lastModified() );
00347                                 }
00348                         }
00349                         $tpl->set( 'copyright', $this->getCopyright() );
00350                 }
00351                 wfProfileOut( __METHOD__ . '-stuff3' );
00352 
00353                 wfProfileIn( __METHOD__ . '-stuff4' );
00354                 $tpl->set( 'copyrightico', $this->getCopyrightIcon() );
00355                 $tpl->set( 'poweredbyico', $this->getPoweredBy() );
00356                 $tpl->set( 'disclaimer', $this->disclaimerLink() );
00357                 $tpl->set( 'privacy', $this->privacyLink() );
00358                 $tpl->set( 'about', $this->aboutLink() );
00359 
00360                 $tpl->set( 'footerlinks', array(
00361                         'info' => array(
00362                                 'lastmod',
00363                                 'viewcount',
00364                                 'numberofwatchingusers',
00365                                 'credits',
00366                                 'copyright',
00367                         ),
00368                         'places' => array(
00369                                 'privacy',
00370                                 'about',
00371                                 'disclaimer',
00372                         ),
00373                 ) );
00374 
00375                 global $wgFooterIcons;
00376                 $tpl->set( 'footericons', $wgFooterIcons );
00377                 foreach ( $tpl->data['footericons'] as $footerIconsKey => &$footerIconsBlock ) {
00378                         if ( count( $footerIconsBlock ) > 0 ) {
00379                                 foreach ( $footerIconsBlock as &$footerIcon ) {
00380                                         if ( isset( $footerIcon['src'] ) ) {
00381                                                 if ( !isset( $footerIcon['width'] ) ) {
00382                                                         $footerIcon['width'] = 88;
00383                                                 }
00384                                                 if ( !isset( $footerIcon['height'] ) ) {
00385                                                         $footerIcon['height'] = 31;
00386                                                 }
00387                                         }
00388                                 }
00389                         } else {
00390                                 unset( $tpl->data['footericons'][$footerIconsKey] );
00391                         }
00392                 }
00393 
00394                 if ( $wgDebugComments ) {
00395                         $tpl->setRef( 'debug', $out->mDebugtext );
00396                 } else {
00397                         $tpl->set( 'debug', '' );
00398                 }
00399 
00400                 $tpl->set( 'sitenotice', $this->getSiteNotice() );
00401                 $tpl->set( 'bottomscripts', $this->bottomScripts() );
00402                 $tpl->set( 'printfooter', $this->printSource() );
00403 
00404                 # An ID that includes the actual body text; without categories, contentSub, ...
00405                 $realBodyAttribs = array( 'id' => 'mw-content-text' );
00406 
00407                 # Add a mw-content-ltr/rtl class to be able to style based on text direction
00408                 # when the content is different from the UI language, i.e.:
00409                 # not for special pages or file pages AND only when viewing AND if the page exists
00410                 # (or is in MW namespace, because that has default content)
00411                 if( !in_array( $title->getNamespace(), array( NS_SPECIAL, NS_FILE ) ) &&
00412                         in_array( $request->getVal( 'action', 'view' ), array( 'view', 'historysubmit' ) ) &&
00413                         ( $title->exists() || $title->getNamespace() == NS_MEDIAWIKI ) ) {
00414                         $pageLang = $title->getPageLanguage();
00415                         $realBodyAttribs['lang'] = $pageLang->getHtmlCode();
00416                         $realBodyAttribs['dir'] = $pageLang->getDir();
00417                         $realBodyAttribs['class'] = 'mw-content-'.$pageLang->getDir();
00418                 }
00419 
00420                 $out->mBodytext = Html::rawElement( 'div', $realBodyAttribs, $out->mBodytext );
00421                 $tpl->setRef( 'bodytext', $out->mBodytext );
00422 
00423                 # Language links
00424                 $language_urls = array();
00425 
00426                 if ( !$wgHideInterlanguageLinks ) {
00427                         foreach( $out->getLanguageLinks() as $l ) {
00428                                 $tmp = explode( ':', $l, 2 );
00429                                 $class = 'interwiki-' . $tmp[0];
00430                                 unset( $tmp );
00431                                 $nt = Title::newFromText( $l );
00432                                 if ( $nt ) {
00433                                         $language_urls[] = array(
00434                                                 'href' => $nt->getFullURL(),
00435                                                 'text' => ( $wgContLang->getLanguageName( $nt->getInterwiki() ) != '' ?
00436                                                                         $wgContLang->getLanguageName( $nt->getInterwiki() ) : $l ),
00437                                                 'title' => $nt->getText(),
00438                                                 'class' => $class,
00439                                                 'lang' => $nt->getInterwiki(),
00440                                                 'hreflang' => $nt->getInterwiki(),
00441                                         );
00442                                 }
00443                         }
00444                 }
00445                 if( count( $language_urls ) ) {
00446                         $tpl->setRef( 'language_urls', $language_urls );
00447                 } else {
00448                         $tpl->set( 'language_urls', false );
00449                 }
00450                 wfProfileOut( __METHOD__ . '-stuff4' );
00451 
00452                 wfProfileIn( __METHOD__ . '-stuff5' );
00453                 # Personal toolbar
00454                 $tpl->set( 'personal_urls', $this->buildPersonalUrls() );
00455                 $content_navigation = $this->buildContentNavigationUrls();
00456                 $content_actions = $this->buildContentActionUrls( $content_navigation );
00457                 $tpl->setRef( 'content_navigation', $content_navigation );
00458                 $tpl->setRef( 'content_actions', $content_actions );
00459 
00460                 $tpl->set( 'sidebar', $this->buildSidebar() );
00461                 $tpl->set( 'nav_urls', $this->buildNavUrls() );
00462 
00463                 // Set the head scripts near the end, in case the above actions resulted in added scripts
00464                 if ( $this->useHeadElement ) {
00465                         $tpl->set( 'headelement', $out->headElement( $this ) );
00466                 } else {
00467                         $tpl->set( 'headscripts', $out->getHeadScripts() . $out->getHeadItems() );
00468                 }
00469 
00470                 $tpl->set( 'debughtml', $this->generateDebugHTML() );
00471                 $tpl->set( 'reporttime', wfReportTime() );
00472 
00473                 // original version by hansm
00474                 if( !wfRunHooks( 'SkinTemplateOutputPageBeforeExec', array( &$this, &$tpl ) ) ) {
00475                         wfDebug( __METHOD__ . ": Hook SkinTemplateOutputPageBeforeExec broke outputPage execution!\n" );
00476                 }
00477 
00478                 // Set the bodytext to another key so that skins can just output it on it's own
00479                 // and output printfooter and debughtml separately
00480                 $tpl->set( 'bodycontent', $tpl->data['bodytext'] );
00481 
00482                 // Append printfooter and debughtml onto bodytext so that skins that were already
00483                 // using bodytext before they were split out don't suddenly start not outputting information
00484                 $tpl->data['bodytext'] .= Html::rawElement( 'div', array( 'class' => 'printfooter' ), "\n{$tpl->data['printfooter']}" ) . "\n";
00485                 $tpl->data['bodytext'] .= $tpl->data['debughtml'];
00486 
00487                 // allow extensions adding stuff after the page content.
00488                 // See Skin::afterContentHook() for further documentation.
00489                 $tpl->set( 'dataAfterContent', $this->afterContentHook() );
00490                 wfProfileOut( __METHOD__ . '-stuff5' );
00491 
00492                 // execute template
00493                 wfProfileIn( __METHOD__ . '-execute' );
00494                 $res = $tpl->execute();
00495                 wfProfileOut( __METHOD__ . '-execute' );
00496 
00497                 // result may be an error
00498                 $this->printOrError( $res );
00499 
00500                 if ( $oldContext ) {
00501                         $this->setContext( $oldContext );
00502                 }
00503                 wfProfileOut( __METHOD__ );
00504         }
00505 
00514         function printOrError( $str ) {
00515                 echo $str;
00516         }
00517 
00526         function useCombinedLoginLink() {
00527                 global $wgUseCombinedLoginLink;
00528                 return $wgUseCombinedLoginLink;
00529         }
00530 
00535         protected function buildPersonalUrls() {
00536                 $title = $this->getTitle();
00537                 $request = $this->getRequest();
00538                 $pageurl = $title->getLocalURL();
00539                 wfProfileIn( __METHOD__ );
00540 
00541                 /* set up the default links for the personal toolbar */
00542                 $personal_urls = array();
00543 
00544                 # Due to bug 32276, if a user does not have read permissions,
00545                 # $this->getTitle() will just give Special:Badtitle, which is
00546                 # not especially useful as a returnto parameter. Use the title
00547                 # from the request instead, if there was one.
00548                 $page = Title::newFromURL( $request->getVal( 'title', '' ) );
00549                 $page = $request->getVal( 'returnto', $page );
00550                 $a = array();
00551                 if ( strval( $page ) !== '' ) {
00552                         $a['returnto'] = $page;
00553                         $query = $request->getVal( 'returntoquery', $this->thisquery );
00554                         if( $query != '' ) {
00555                                 $a['returntoquery'] = $query;
00556                         }
00557                 }
00558                 $returnto = wfArrayToCGI( $a );
00559                 if( $this->loggedin ) {
00560                         $personal_urls['userpage'] = array(
00561                                 'text' => $this->username,
00562                                 'href' => &$this->userpageUrlDetails['href'],
00563                                 'class' => $this->userpageUrlDetails['exists'] ? false : 'new',
00564                                 'active' => ( $this->userpageUrlDetails['href'] == $pageurl )
00565                         );
00566                         $usertalkUrlDetails = $this->makeTalkUrlDetails( $this->userpage );
00567                         $personal_urls['mytalk'] = array(
00568                                 'text' => $this->msg( 'mytalk' )->text(),
00569                                 'href' => &$usertalkUrlDetails['href'],
00570                                 'class' => $usertalkUrlDetails['exists'] ? false : 'new',
00571                                 'active' => ( $usertalkUrlDetails['href'] == $pageurl )
00572                         );
00573                         $href = self::makeSpecialUrl( 'Preferences' );
00574                         $personal_urls['preferences'] = array(
00575                                 'text' => $this->msg( 'mypreferences' )->text(),
00576                                 'href' => $href,
00577                                 'active' => ( $href == $pageurl )
00578                         );
00579                         $href = self::makeSpecialUrl( 'Watchlist' );
00580                         $personal_urls['watchlist'] = array(
00581                                 'text' => $this->msg( 'mywatchlist' )->text(),
00582                                 'href' => $href,
00583                                 'active' => ( $href == $pageurl )
00584                         );
00585 
00586                         # We need to do an explicit check for Special:Contributions, as we
00587                         # have to match both the title, and the target (which could come
00588                         # from request values or be specified in "sub page" form. The plot
00589                         # thickens, because the Title object is altered for special pages,
00590                         # so doesn't contain the original alias-with-subpage.
00591                         $origTitle = Title::newFromText( $request->getText( 'title' ) );
00592                         if( $origTitle instanceof Title && $origTitle->isSpecialPage() ) {
00593                                 list( $spName, $spPar ) = SpecialPageFactory::resolveAlias( $origTitle->getText() );
00594                                 $active = $spName == 'Contributions'
00595                                         && ( ( $spPar && $spPar == $this->username )
00596                                                 || $request->getText( 'target' ) == $this->username );
00597                         } else {
00598                                 $active = false;
00599                         }
00600 
00601                         $href = self::makeSpecialUrlSubpage( 'Contributions', $this->username );
00602                         $personal_urls['mycontris'] = array(
00603                                 'text' => $this->msg( 'mycontris' )->text(),
00604                                 'href' => $href,
00605                                 'active' => $active
00606                         );
00607                         $personal_urls['logout'] = array(
00608                                 'text' => $this->msg( 'userlogout' )->text(),
00609                                 'href' => self::makeSpecialUrl( 'Userlogout',
00610                                         // userlogout link must always contain an & character, otherwise we might not be able
00611                                         // to detect a buggy precaching proxy (bug 17790)
00612                                         $title->isSpecial( 'Preferences' ) ? 'noreturnto' : $returnto
00613                                 ),
00614                                 'active' => false
00615                         );
00616                 } else {
00617                         $useCombinedLoginLink = $this->useCombinedLoginLink();
00618                         $loginlink = $this->getUser()->isAllowed( 'createaccount' ) && $useCombinedLoginLink
00619                                 ? 'nav-login-createaccount'
00620                                 : 'login';
00621                         $is_signup = $request->getText('type') == "signup";
00622 
00623                         # anonlogin & login are the same
00624                         $login_url = array(
00625                                 'text' => $this->msg( $loginlink )->text(),
00626                                 'href' => self::makeSpecialUrl( 'Userlogin', $returnto ),
00627                                 'active' => $title->isSpecial( 'Userlogin' ) && ( $loginlink == "nav-login-createaccount" || !$is_signup )
00628                         );
00629                         if ( $this->getUser()->isAllowed( 'createaccount' ) && !$useCombinedLoginLink ) {
00630                                 $createaccount_url = array(
00631                                         'text' => $this->msg( 'createaccount' )->text(),
00632                                         'href' => self::makeSpecialUrl( 'Userlogin', "$returnto&type=signup" ),
00633                                         'active' => $title->isSpecial( 'Userlogin' ) && $is_signup
00634                                 );
00635                         }
00636                         global $wgServer, $wgSecureLogin;
00637                         if( substr( $wgServer, 0, 5 ) === 'http:' && $wgSecureLogin ) {
00638                                 $title = SpecialPage::getTitleFor( 'Userlogin' );
00639                                 $https_url = preg_replace( '/^http:/', 'https:', $title->getFullURL() );
00640                                 $login_url['href']  = $https_url;
00641                                 # @todo FIXME: Class depends on skin
00642                                 $login_url['class'] = 'link-https';
00643                                 if ( isset($createaccount_url) ) {
00644                                         $https_url = preg_replace( '/^http:/', 'https:',
00645                                                 $title->getFullURL("type=signup") );
00646                                         $createaccount_url['href']  = $https_url;
00647                                         # @todo FIXME: Class depends on skin
00648                                         $createaccount_url['class'] = 'link-https';
00649                                 }
00650                         }
00651 
00652 
00653                         if( $this->showIPinHeader() ) {
00654                                 $href = &$this->userpageUrlDetails['href'];
00655                                 $personal_urls['anonuserpage'] = array(
00656                                         'text' => $this->username,
00657                                         'href' => $href,
00658                                         'class' => $this->userpageUrlDetails['exists'] ? false : 'new',
00659                                         'active' => ( $pageurl == $href )
00660                                 );
00661                                 $usertalkUrlDetails = $this->makeTalkUrlDetails( $this->userpage );
00662                                 $href = &$usertalkUrlDetails['href'];
00663                                 $personal_urls['anontalk'] = array(
00664                                         'text' => $this->msg( 'anontalk' )->text(),
00665                                         'href' => $href,
00666                                         'class' => $usertalkUrlDetails['exists'] ? false : 'new',
00667                                         'active' => ( $pageurl == $href )
00668                                 );
00669                                 $personal_urls['anonlogin'] = $login_url;
00670                         } else {
00671                                 $personal_urls['login'] = $login_url;
00672                         }
00673                         if ( isset($createaccount_url) ) {
00674                                 $personal_urls['createaccount'] = $createaccount_url;
00675                         }
00676                 }
00677 
00678                 wfRunHooks( 'PersonalUrls', array( &$personal_urls, &$title ) );
00679                 wfProfileOut( __METHOD__ );
00680                 return $personal_urls;
00681         }
00682 
00692         function tabAction( $title, $message, $selected, $query = '', $checkEdit = false ) {
00693                 $classes = array();
00694                 if( $selected ) {
00695                         $classes[] = 'selected';
00696                 }
00697                 if( $checkEdit && !$title->isKnown() ) {
00698                         $classes[] = 'new';
00699                         $query = 'action=edit&redlink=1';
00700                 }
00701 
00702                 // wfMessageFallback will nicely accept $message as an array of fallbacks
00703                 // or just a single key
00704                 $msg = wfMessageFallback( $message )->setContext( $this->getContext() );
00705                 if ( is_array($message) ) {
00706                         // for hook compatibility just keep the last message name
00707                         $message = end($message);
00708                 }
00709                 if ( $msg->exists() ) {
00710                         $text = $msg->text();
00711                 } else {
00712                         global $wgContLang;
00713                         $text = $wgContLang->getFormattedNsText(
00714                                 MWNamespace::getSubject( $title->getNamespace() ) );
00715                 }
00716 
00717                 $result = array();
00718                 if( !wfRunHooks( 'SkinTemplateTabAction', array( &$this,
00719                                 $title, $message, $selected, $checkEdit,
00720                                 &$classes, &$query, &$text, &$result ) ) ) {
00721                         return $result;
00722                 }
00723 
00724                 return array(
00725                         'class' => implode( ' ', $classes ),
00726                         'text' => $text,
00727                         'href' => $title->getLocalUrl( $query ),
00728                         'primary' => true );
00729         }
00730 
00731         function makeTalkUrlDetails( $name, $urlaction = '' ) {
00732                 $title = Title::newFromText( $name );
00733                 if( !is_object( $title ) ) {
00734                         throw new MWException( __METHOD__ . " given invalid pagename $name" );
00735                 }
00736                 $title = $title->getTalkPage();
00737                 self::checkTitle( $title, $name );
00738                 return array(
00739                         'href' => $title->getLocalURL( $urlaction ),
00740                         'exists' => $title->getArticleID() != 0,
00741                 );
00742         }
00743 
00744         function makeArticleUrlDetails( $name, $urlaction = '' ) {
00745                 $title = Title::newFromText( $name );
00746                 $title= $title->getSubjectPage();
00747                 self::checkTitle( $title, $name );
00748                 return array(
00749                         'href' => $title->getLocalURL( $urlaction ),
00750                         'exists' => $title->getArticleID() != 0,
00751                 );
00752         }
00753 
00787         protected function buildContentNavigationUrls() {
00788                 global $wgDisableLangConversion;
00789 
00790                 wfProfileIn( __METHOD__ );
00791 
00792                 $title = $this->getRelevantTitle(); // Display tabs for the relevant title rather than always the title itself
00793                 $onPage = $title->equals($this->getTitle());
00794 
00795                 $out = $this->getOutput();
00796                 $request = $this->getRequest();
00797                 $user = $this->getUser();
00798 
00799                 $content_navigation = array(
00800                         'namespaces' => array(),
00801                         'views' => array(),
00802                         'actions' => array(),
00803                         'variants' => array()
00804                 );
00805 
00806                 // parameters
00807                 $action = $request->getVal( 'action', 'view' );
00808 
00809                 $userCanRead = $title->quickUserCan( 'read', $user );
00810 
00811                 $preventActiveTabs = false;
00812                 wfRunHooks( 'SkinTemplatePreventOtherActiveTabs', array( &$this, &$preventActiveTabs ) );
00813 
00814                 // Checks if page is some kind of content
00815                 if( $title->canExist() ) {
00816                         // Gets page objects for the related namespaces
00817                         $subjectPage = $title->getSubjectPage();
00818                         $talkPage = $title->getTalkPage();
00819 
00820                         // Determines if this is a talk page
00821                         $isTalk = $title->isTalkPage();
00822 
00823                         // Generates XML IDs from namespace names
00824                         $subjectId = $title->getNamespaceKey( '' );
00825 
00826                         if ( $subjectId == 'main' ) {
00827                                 $talkId = 'talk';
00828                         } else {
00829                                 $talkId = "{$subjectId}_talk";
00830                         }
00831 
00832                         $skname = $this->skinname;
00833 
00834                         // Adds namespace links
00835                         $subjectMsg = array( "nstab-$subjectId" );
00836                         if ( $subjectPage->isMainPage() ) {
00837                                 array_unshift($subjectMsg, 'mainpage-nstab');
00838                         }
00839                         $content_navigation['namespaces'][$subjectId] = $this->tabAction(
00840                                 $subjectPage, $subjectMsg, !$isTalk && !$preventActiveTabs, '', $userCanRead
00841                         );
00842                         $content_navigation['namespaces'][$subjectId]['context'] = 'subject';
00843                         $content_navigation['namespaces'][$talkId] = $this->tabAction(
00844                                 $talkPage, array( "nstab-$talkId", 'talk' ), $isTalk && !$preventActiveTabs, '', $userCanRead
00845                         );
00846                         $content_navigation['namespaces'][$talkId]['context'] = 'talk';
00847 
00848                         if ( $userCanRead ) {
00849                                 // Adds view view link
00850                                 if ( $title->exists() ) {
00851                                         $content_navigation['views']['view'] = $this->tabAction(
00852                                                 $isTalk ? $talkPage : $subjectPage,
00853                                                 array( "$skname-view-view", 'view' ),
00854                                                 ( $onPage && ($action == 'view' || $action == 'purge' ) ), '', true
00855                                         );
00856                                         $content_navigation['views']['view']['redundant'] = true; // signal to hide this from simple content_actions
00857                                 }
00858 
00859                                 wfProfileIn( __METHOD__ . '-edit' );
00860 
00861                                 // Checks if user can edit the current page if it exists or create it otherwise
00862                                 if ( $title->quickUserCan( 'edit', $user ) && ( $title->exists() || $title->quickUserCan( 'create', $user ) ) ) {
00863                                         // Builds CSS class for talk page links
00864                                         $isTalkClass = $isTalk ? ' istalk' : '';
00865                                         // Whether the user is editing the page
00866                                         $isEditing = $onPage && ( $action == 'edit' || $action == 'submit' );
00867                                         // Whether to show the "Add a new section" tab
00868                                         // Checks if this is a current rev of talk page and is not forced to be hidden
00869                                         $showNewSection = !$out->forceHideNewSectionLink()
00870                                                 && ( ( $isTalk && $this->isRevisionCurrent() ) || $out->showNewSectionLink() );
00871                                         $section = $request->getVal( 'section' );
00872 
00873                                         $msgKey = $title->exists() || ( $title->getNamespace() == NS_MEDIAWIKI && $title->getDefaultMessageText() !== false ) ?
00874                                                 "edit" : "create";
00875                                         $content_navigation['views']['edit'] = array(
00876                                                 'class' => ( $isEditing && ( $section !== 'new' || !$showNewSection ) ? 'selected' : '' ) . $isTalkClass,
00877                                                 'text' => wfMessageFallback( "$skname-view-$msgKey", $msgKey )->setContext( $this->getContext() )->text(),
00878                                                 'href' => $title->getLocalURL( $this->editUrlOptions() ),
00879                                                 'primary' => true, // don't collapse this in vector
00880                                         );
00881                                         
00882                                         // section link
00883                                         if ( $showNewSection ) {
00884                                                 // Adds new section link
00885                                                 //$content_navigation['actions']['addsection']
00886                                                 $content_navigation['views']['addsection'] = array(
00887                                                         'class' => ( $isEditing && $section == 'new' ) ? 'selected' : false,
00888                                                         'text' => wfMessageFallback( "$skname-action-addsection", 'addsection' )->setContext( $this->getContext() )->text(),
00889                                                         'href' => $title->getLocalURL( 'action=edit&section=new' )
00890                                                 );
00891                                         }
00892                                 // Checks if the page has some kind of viewable content
00893                                 } elseif ( $title->hasSourceText() ) {
00894                                         // Adds view source view link
00895                                         $content_navigation['views']['viewsource'] = array(
00896                                                 'class' => ( $onPage && $action == 'edit' ) ? 'selected' : false,
00897                                                 'text' => wfMessageFallback( "$skname-action-viewsource", 'viewsource' )->setContext( $this->getContext() )->text(),
00898                                                 'href' => $title->getLocalURL( $this->editUrlOptions() ),
00899                                                 'primary' => true, // don't collapse this in vector
00900                                         );
00901                                 }
00902                                 wfProfileOut( __METHOD__ . '-edit' );
00903 
00904                                 wfProfileIn( __METHOD__ . '-live' );
00905                                 // Checks if the page exists
00906                                 if ( $title->exists() ) {
00907                                         // Adds history view link
00908                                         $content_navigation['views']['history'] = array(
00909                                                 'class' => ( $onPage && $action == 'history' ) ? 'selected' : false,
00910                                                 'text' => wfMessageFallback( "$skname-view-history", 'history_short' )->setContext( $this->getContext() )->text(),
00911                                                 'href' => $title->getLocalURL( 'action=history' ),
00912                                                 'rel' => 'archives',
00913                                         );
00914 
00915                                         if ( $title->quickUserCan( 'delete', $user ) ) {
00916                                                 $content_navigation['actions']['delete'] = array(
00917                                                         'class' => ( $onPage && $action == 'delete' ) ? 'selected' : false,
00918                                                         'text' => wfMessageFallback( "$skname-action-delete", 'delete' )->setContext( $this->getContext() )->text(),
00919                                                         'href' => $title->getLocalURL( 'action=delete' )
00920                                                 );
00921                                         }
00922 
00923                                         if ( $title->quickUserCan( 'move', $user ) ) {
00924                                                 $moveTitle = SpecialPage::getTitleFor( 'Movepage', $title->getPrefixedDBkey() );
00925                                                 $content_navigation['actions']['move'] = array(
00926                                                         'class' => $this->getTitle()->isSpecial( 'Movepage' ) ? 'selected' : false,
00927                                                         'text' => wfMessageFallback( "$skname-action-move", 'move' )->setContext( $this->getContext() )->text(),
00928                                                         'href' => $moveTitle->getLocalURL()
00929                                                 );
00930                                         }
00931                                 } else {
00932                                         // article doesn't exist or is deleted
00933                                         if ( $user->isAllowed( 'deletedhistory' ) ) {
00934                                                 $n = $title->isDeleted();
00935                                                 if( $n ) {
00936                                                         $undelTitle = SpecialPage::getTitleFor( 'Undelete' );
00937                                                         // If the user can't undelete but can view deleted history show them a "View .. deleted" tab instead
00938                                                         $msgKey = $user->isAllowed( 'undelete' ) ? 'undelete' : 'viewdeleted';
00939                                                         $content_navigation['actions']['undelete'] = array(
00940                                                                 'class' => $this->getTitle()->isSpecial( 'Undelete' ) ? 'selected' : false,
00941                                                                 'text' => wfMessageFallback( "$skname-action-$msgKey", "{$msgKey}_short" )
00942                                                                         ->setContext( $this->getContext() )->numParams( $n )->text(),
00943                                                                 'href' => $undelTitle->getLocalURL( array( 'target' => $title->getPrefixedDBkey() ) )
00944                                                         );
00945                                                 }
00946                                         }
00947                                 }
00948 
00949                                 if ( $title->getNamespace() !== NS_MEDIAWIKI && $title->quickUserCan( 'protect', $user ) ) {
00950                                         $mode = $title->isProtected() ? 'unprotect' : 'protect';
00951                                         $content_navigation['actions'][$mode] = array(
00952                                                 'class' => ( $onPage && $action == $mode ) ? 'selected' : false,
00953                                                 'text' => wfMessageFallback( "$skname-action-$mode", $mode )->setContext( $this->getContext() )->text(),
00954                                                 'href' => $title->getLocalURL( "action=$mode" )
00955                                         );
00956                                 }
00957 
00958                                 wfProfileOut( __METHOD__ . '-live' );
00959 
00960                                 // Checks if the user is logged in
00961                                 if ( $this->loggedin ) {
00971                                         $mode = $title->userIsWatching() ? 'unwatch' : 'watch';
00972                                         $token = WatchAction::getWatchToken( $title, $user, $mode );
00973                                         $content_navigation['actions'][$mode] = array(
00974                                                 'class' => $onPage && ( $action == 'watch' || $action == 'unwatch' ) ? 'selected' : false,
00975                                                 'text' => $this->msg( $mode )->text(), // uses 'watch' or 'unwatch' message
00976                                                 'href' => $title->getLocalURL( array( 'action' => $mode, 'token' => $token ) )
00977                                         );
00978                                 }
00979                         }
00980 
00981                         wfRunHooks( 'SkinTemplateNavigation', array( &$this, &$content_navigation ) );
00982 
00983                         if ( $userCanRead && !$wgDisableLangConversion ) {
00984                                 $pageLang = $title->getPageLanguage();
00985                                 // Gets list of language variants
00986                                 $variants = $pageLang->getVariants();
00987                                 // Checks that language conversion is enabled and variants exist
00988                                 // And if it is not in the special namespace
00989                                 if( count( $variants ) > 1 ) {
00990                                         // Gets preferred variant (note that user preference is 
00991                                         // only possible for wiki content language variant)
00992                                         $preferred = $pageLang->getPreferredVariant();
00993                                         // Loops over each variant
00994                                         foreach( $variants as $code ) {
00995                                                 // Gets variant name from language code
00996                                                 $varname = $pageLang->getVariantname( $code );
00997                                                 // Checks if the variant is marked as disabled
00998                                                 if( $varname == 'disable' ) {
00999                                                         // Skips this variant
01000                                                         continue;
01001                                                 }
01002                                                 // Appends variant link
01003                                                 $content_navigation['variants'][] = array(
01004                                                         'class' => ( $code == $preferred ) ? 'selected' : false,
01005                                                         'text' => $varname,
01006                                                         'href' => $title->getLocalURL( array( 'variant' => $code ) )
01007                                                 );
01008                                         }
01009                                 }
01010                         }
01011                 } else {
01012                         // If it's not content, it's got to be a special page
01013                         $content_navigation['namespaces']['special'] = array(
01014                                 'class' => 'selected',
01015                                 'text' => $this->msg( 'nstab-special' )->text(),
01016                                 'href' => $request->getRequestURL(), // @bug 2457, 2510
01017                                 'context' => 'subject'
01018                         );
01019 
01020                         wfRunHooks( 'SkinTemplateNavigation::SpecialPage',
01021                                 array( &$this, &$content_navigation ) );
01022                 }
01023 
01024                 // Equiv to SkinTemplateContentActions
01025                 wfRunHooks( 'SkinTemplateNavigation::Universal', array( &$this,  &$content_navigation ) );
01026 
01027                 // Setup xml ids and tooltip info
01028                 foreach ( $content_navigation as $section => &$links ) {
01029                         foreach ( $links as $key => &$link ) {
01030                                 $xmlID = $key;
01031                                 if ( isset( $link['context'] ) && $link['context'] == 'subject' ) {
01032                                         $xmlID = 'ca-nstab-' . $xmlID;
01033                                 } elseif ( isset( $link['context'] ) && $link['context'] == 'talk' ) {
01034                                         $xmlID = 'ca-talk';
01035                                 } elseif ( $section == "variants" ) {
01036                                         $xmlID = 'ca-varlang-' . $xmlID;
01037                                 } else {
01038                                         $xmlID = 'ca-' . $xmlID;
01039                                 }
01040                                 $link['id'] = $xmlID;
01041                         }
01042                 }
01043 
01044                 # We don't want to give the watch tab an accesskey if the
01045                 # page is being edited, because that conflicts with the
01046                 # accesskey on the watch checkbox.  We also don't want to
01047                 # give the edit tab an accesskey, because that's fairly su-
01048                 # perfluous and conflicts with an accesskey (Ctrl-E) often
01049                 # used for editing in Safari.
01050                 if( in_array( $action, array( 'edit', 'submit' ) ) ) {
01051                         if ( isset($content_navigation['views']['edit']) ) {
01052                                 $content_navigation['views']['edit']['tooltiponly'] = true;
01053                         }
01054                         if ( isset($content_navigation['actions']['watch']) ) {
01055                                 $content_navigation['actions']['watch']['tooltiponly'] = true;
01056                         }
01057                         if ( isset($content_navigation['actions']['unwatch']) ) {
01058                                 $content_navigation['actions']['unwatch']['tooltiponly'] = true;
01059                         }
01060                 }
01061 
01062                 wfProfileOut( __METHOD__ );
01063 
01064                 return $content_navigation;
01065         }
01066 
01072         function buildContentActionUrls( $content_navigation ) {
01073 
01074                 wfProfileIn( __METHOD__ );
01075 
01076                 // content_actions has been replaced with content_navigation for backwards
01077                 // compatibility and also for skins that just want simple tabs content_actions
01078                 // is now built by flattening the content_navigation arrays into one
01079 
01080                 $content_actions = array();
01081 
01082                 foreach ( $content_navigation as $links ) {
01083 
01084                         foreach ( $links as $key => $value ) {
01085 
01086                                 if ( isset($value["redundant"]) && $value["redundant"] ) {
01087                                         // Redundant tabs are dropped from content_actions
01088                                         continue;
01089                                 }
01090 
01091                                 // content_actions used to have ids built using the "ca-$key" pattern
01092                                 // so the xmlID based id is much closer to the actual $key that we want
01093                                 // for that reason we'll just strip out the ca- if present and use
01094                                 // the latter potion of the "id" as the $key
01095                                 if ( isset($value["id"]) && substr($value["id"], 0, 3) == "ca-" ) {
01096                                         $key = substr($value["id"], 3);
01097                                 }
01098 
01099                                 if ( isset($content_actions[$key]) ) {
01100                                         wfDebug( __METHOD__ . ": Found a duplicate key for $key while flattening content_navigation into content_actions." );
01101                                         continue;
01102                                 }
01103 
01104                                 $content_actions[$key] = $value;
01105 
01106                         }
01107 
01108                 }
01109 
01110                 wfProfileOut( __METHOD__ );
01111 
01112                 return $content_actions;
01113         }
01114 
01120         protected function buildNavUrls() {
01121                 global $wgUploadNavigationUrl;
01122 
01123                 wfProfileIn( __METHOD__ );
01124 
01125                 $out = $this->getOutput();
01126                 $request = $this->getRequest();
01127 
01128                 $nav_urls = array();
01129                 $nav_urls['mainpage'] = array( 'href' => self::makeMainPageUrl() );
01130                 if( $wgUploadNavigationUrl ) {
01131                         $nav_urls['upload'] = array( 'href' => $wgUploadNavigationUrl );
01132                 } elseif( UploadBase::isEnabled() && UploadBase::isAllowed( $this->getUser() ) === true ) {
01133                         $nav_urls['upload'] = array( 'href' => self::makeSpecialUrl( 'Upload' ) );
01134                 } else {
01135                         $nav_urls['upload'] = false;
01136                 }
01137                 $nav_urls['specialpages'] = array( 'href' => self::makeSpecialUrl( 'Specialpages' ) );
01138 
01139                 $nav_urls['print'] = false;
01140                 $nav_urls['permalink'] = false;
01141                 $nav_urls['whatlinkshere'] = false;
01142                 $nav_urls['recentchangeslinked'] = false;
01143                 $nav_urls['contributions'] = false;
01144                 $nav_urls['log'] = false;
01145                 $nav_urls['blockip'] = false;
01146                 $nav_urls['emailuser'] = false;
01147 
01148                 // A print stylesheet is attached to all pages, but nobody ever
01149                 // figures that out. :)  Add a link...
01150                 if( $out->isArticle() ) {
01151                         if ( !$out->isPrintable() ) {
01152                                 $nav_urls['print'] = array(
01153                                         'text' => $this->msg( 'printableversion' )->text(),
01154                                         'href' => $this->getTitle()->getLocalURL(
01155                                                 $request->appendQueryValue( 'printable', 'yes', true ) )
01156                                 );
01157                         }
01158 
01159                         // Also add a "permalink" while we're at it
01160                         $revid = $this->getRevisionId();
01161                         if ( $revid ) {
01162                                 $nav_urls['permalink'] = array(
01163                                         'text' => $this->msg( 'permalink' )->text(),
01164                                         'href' => $out->getTitle()->getLocalURL( "oldid=$revid" )
01165                                 );
01166                         }
01167 
01168                         // Use the copy of revision ID in case this undocumented, shady hook tries to mess with internals
01169                         wfRunHooks( 'SkinTemplateBuildNavUrlsNav_urlsAfterPermalink',
01170                                 array( &$this, &$nav_urls, &$revid, &$revid ) );
01171                 }
01172 
01173                 if ( $out->isArticleRelated() ) {
01174                         $nav_urls['whatlinkshere'] = array(
01175                                 'href' => SpecialPage::getTitleFor( 'Whatlinkshere', $this->thispage )->getLocalUrl()
01176                         );
01177                         if ( $this->getTitle()->getArticleId() ) {
01178                                 $nav_urls['recentchangeslinked'] = array(
01179                                         'href' => SpecialPage::getTitleFor( 'Recentchangeslinked', $this->thispage )->getLocalUrl()
01180                                 );
01181                         }
01182                 }
01183 
01184                 $user = $this->getRelevantUser();
01185                 if ( $user ) {
01186                         $rootUser = $user->getName();
01187 
01188                         $nav_urls['contributions'] = array(
01189                                 'href' => self::makeSpecialUrlSubpage( 'Contributions', $rootUser )
01190                         );
01191 
01192                         if ( $user->isLoggedIn() ) {
01193                                 $logPage = SpecialPage::getTitleFor( 'Log' );
01194                                 $nav_urls['log'] = array(
01195                                         'href' => $logPage->getLocalUrl( array( 'user' => $rootUser ) )
01196                                 );
01197                         }
01198 
01199                         if ( $this->getUser()->isAllowed( 'block' ) ) {
01200                                 $nav_urls['blockip'] = array(
01201                                         'href' => self::makeSpecialUrlSubpage( 'Block', $rootUser )
01202                                 );
01203                         }
01204 
01205                         if ( $this->showEmailUser( $user ) ) {
01206                                 $nav_urls['emailuser'] = array(
01207                                         'href' => self::makeSpecialUrlSubpage( 'Emailuser', $rootUser )
01208                                 );
01209                         }
01210                 }
01211 
01212                 wfProfileOut( __METHOD__ );
01213                 return $nav_urls;
01214         }
01215 
01221         function getNameSpaceKey() {
01222                 return $this->getTitle()->getNamespaceKey();
01223         }
01224 
01225         public function commonPrintStylesheet() {
01226                 return false;
01227         }
01228 }
01229 
01235 abstract class QuickTemplate {
01239         public function QuickTemplate() {
01240                 $this->data = array();
01241                 $this->translator = new MediaWiki_I18N();
01242         }
01243 
01249         public function set( $name, $value ) {
01250                 $this->data[$name] = $value;
01251         }
01252 
01257         public function setRef( $name, &$value ) {
01258                 $this->data[$name] =& $value;
01259         }
01260 
01264         public function setTranslator( &$t ) {
01265                 $this->translator = &$t;
01266         }
01267 
01272         abstract public function execute();
01273 
01277         function text( $str ) {
01278                 echo htmlspecialchars( $this->data[$str] );
01279         }
01280 
01284         function jstext( $str ) {
01285                 echo Xml::escapeJsString( $this->data[$str] );
01286         }
01287 
01291         function html( $str ) {
01292                 echo $this->data[$str];
01293         }
01294 
01298         function msg( $str ) {
01299                 echo htmlspecialchars( $this->translator->translate( $str ) );
01300         }
01301 
01305         function msgHtml( $str ) {
01306                 echo $this->translator->translate( $str );
01307         }
01308 
01313         function msgWiki( $str ) {
01314                 global $wgOut;
01315 
01316                 $text = $this->translator->translate( $str );
01317                 echo $wgOut->parse( $text );
01318         }
01319 
01323         function haveData( $str ) {
01324                 return isset( $this->data[$str] );
01325         }
01326 
01332         function haveMsg( $str ) {
01333                 $msg = $this->translator->translate( $str );
01334                 return ( $msg != '-' ) && ( $msg != '' ); # ????
01335         }
01336 
01342         public function getSkin() {
01343                 return $this->data['skin'];
01344         }
01345 }
01346 
01352 abstract class BaseTemplate extends QuickTemplate {
01353 
01360         public function getMsg( $name ) {
01361                 return $this->getSkin()->msg( $name );
01362         }
01363 
01364         function msg( $str ) {
01365                 echo $this->getMsg( $str )->escaped();
01366         }
01367 
01368         function msgHtml( $str ) {
01369                 echo $this->getMsg( $str )->text();
01370         }
01371 
01372         function msgWiki( $str ) {
01373                 echo $this->getMsg( $str )->parseAsBlock();
01374         }
01375 
01382         function getToolbox() {
01383                 wfProfileIn( __METHOD__ );
01384 
01385                 $toolbox = array();
01386                 if ( isset( $this->data['nav_urls']['whatlinkshere'] ) && $this->data['nav_urls']['whatlinkshere'] ) {
01387                         $toolbox['whatlinkshere'] = $this->data['nav_urls']['whatlinkshere'];
01388                         $toolbox['whatlinkshere']['id'] = 't-whatlinkshere';
01389                 }
01390                 if ( isset( $this->data['nav_urls']['recentchangeslinked'] ) && $this->data['nav_urls']['recentchangeslinked'] ) {
01391                         $toolbox['recentchangeslinked'] = $this->data['nav_urls']['recentchangeslinked'];
01392                         $toolbox['recentchangeslinked']['msg'] = 'recentchangeslinked-toolbox';
01393                         $toolbox['recentchangeslinked']['id'] = 't-recentchangeslinked';
01394                 }
01395                 if ( isset( $this->data['feeds'] ) && $this->data['feeds'] ) {
01396                         $toolbox['feeds']['id'] = 'feedlinks';
01397                         $toolbox['feeds']['links'] = array();
01398                         foreach ( $this->data['feeds'] as $key => $feed ) {
01399                                 $toolbox['feeds']['links'][$key] = $feed;
01400                                 $toolbox['feeds']['links'][$key]['id'] = "feed-$key";
01401                                 $toolbox['feeds']['links'][$key]['rel'] = 'alternate';
01402                                 $toolbox['feeds']['links'][$key]['type'] = "application/{$key}+xml";
01403                                 $toolbox['feeds']['links'][$key]['class'] = 'feedlink';
01404                         }
01405                 }
01406                 foreach ( array( 'contributions', 'log', 'blockip', 'emailuser', 'upload', 'specialpages' ) as $special ) {
01407                         if ( isset( $this->data['nav_urls'][$special] ) && $this->data['nav_urls'][$special] ) {
01408                                 $toolbox[$special] = $this->data['nav_urls'][$special];
01409                                 $toolbox[$special]['id'] = "t-$special";
01410                         }
01411                 }
01412                 if ( isset( $this->data['nav_urls']['print'] ) && $this->data['nav_urls']['print'] ) {
01413                         $toolbox['print'] = $this->data['nav_urls']['print'];
01414                         $toolbox['print']['rel'] = 'alternate';
01415                         $toolbox['print']['msg'] = 'printableversion';
01416                 }
01417                 if ( isset( $this->data['nav_urls']['permalink'] ) && $this->data['nav_urls']['permalink'] ) {
01418                         $toolbox['permalink'] = $this->data['nav_urls']['permalink'];
01419                         if( $toolbox['permalink']['href'] === '' ) {
01420                                 unset( $toolbox['permalink']['href'] );
01421                                 $toolbox['ispermalink']['tooltiponly'] = true;
01422                                 $toolbox['ispermalink']['id'] = 't-ispermalink';
01423                                 $toolbox['ispermalink']['msg'] = 'permalink';
01424                         } else {
01425                                 $toolbox['permalink']['id'] = 't-permalink';
01426                         }
01427                 }
01428                 wfRunHooks( 'BaseTemplateToolbox', array( &$this, &$toolbox ) );
01429                 wfProfileOut( __METHOD__ );
01430                 return $toolbox;
01431         }
01432 
01442         function getPersonalTools() {
01443                 $personal_tools = array();
01444                 foreach( $this->data['personal_urls'] as $key => $ptool ) {
01445                         # The class on a personal_urls item is meant to go on the <a> instead
01446                         # of the <li> so we have to use a single item "links" array instead
01447                         # of using most of the personal_url's keys directly
01448                         $personal_tools[$key] = array();
01449                         $personal_tools[$key]["links"][] = array();
01450                         $personal_tools[$key]["links"][0]["single-id"] = $personal_tools[$key]["id"] = "pt-$key";
01451                         if ( isset($ptool["active"]) ) {
01452                                 $personal_tools[$key]["active"] = $ptool["active"];
01453                         }
01454                         foreach ( array("href", "class", "text") as $k ) {
01455                                 if ( isset($ptool[$k]) )
01456                                         $personal_tools[$key]["links"][0][$k] = $ptool[$k];
01457                         }
01458                 }
01459                 return $personal_tools;
01460         }
01461 
01462         function getSidebar( $options = array() ) {
01463                 // Force the rendering of the following portals
01464                 $sidebar = $this->data['sidebar'];
01465                 if ( !isset( $sidebar['SEARCH'] ) ) {
01466                         $sidebar['SEARCH'] = true;
01467                 }
01468                 if ( !isset( $sidebar['TOOLBOX'] ) ) {
01469                         $sidebar['TOOLBOX'] = true;
01470                 }
01471                 if ( !isset( $sidebar['LANGUAGES'] ) ) {
01472                         $sidebar['LANGUAGES'] = true;
01473                 }
01474                 
01475                 if ( !isset( $options['search'] ) || $options['search'] !== true ) {
01476                         unset( $sidebar['SEARCH'] );
01477                 }
01478                 if ( isset( $options['toolbox'] ) && $options['toolbox'] === false ) {
01479                         unset( $sidebar['TOOLBOX'] );
01480                 }
01481                 if ( isset( $options['languages'] ) && $options['languages'] === false ) {
01482                         unset( $sidebar['LANGUAGES'] );
01483                 }
01484                 
01485                 $boxes = array();
01486                 foreach ( $sidebar as $boxName => $content ) {
01487                         if ( $content === false ) {
01488                                 continue;
01489                         }
01490                         switch ( $boxName ) {
01491                         case 'SEARCH':
01492                                 // Search is a special case, skins should custom implement this
01493                                 $boxes[$boxName] = array(
01494                                         'id'        => "p-search",
01495                                         'header'    => $this->getMsg( 'search' )->text(),
01496                                         'generated' => false,
01497                                         'content'   => true,
01498                                 );
01499                                 break;
01500                         case 'TOOLBOX':
01501                                 $msgObj = $this->getMsg( 'toolbox' );
01502                                 $boxes[$boxName] = array(
01503                                         'id'        => "p-tb",
01504                                         'header'    => $msgObj->exists() ? $msgObj->text() : 'toolbox',
01505                                         'generated' => false,
01506                                         'content'   => $this->getToolbox(),
01507                                 );
01508                                 break;
01509                         case 'LANGUAGES':
01510                                 if ( $this->data['language_urls'] ) {
01511                                         $msgObj = $this->getMsg( 'otherlanguages' );
01512                                         $boxes[$boxName] = array(
01513                                                 'id'        => "p-lang",
01514                                                 'header'    => $msgObj->exists() ? $msgObj->text() : 'otherlanguages',
01515                                                 'generated' => false,
01516                                                 'content'   => $this->data['language_urls'],
01517                                         );
01518                                 } 
01519                                 break;
01520                         default:
01521                                 $msgObj = $this->getMsg( $boxName );
01522                                 $boxes[$boxName] = array(
01523                                         'id'        => "p-$boxName",
01524                                         'header'    => $msgObj->exists() ? $msgObj->text() : $boxName,
01525                                         'generated' => true,
01526                                         'content'   => $content,
01527                                 );
01528                                 break;
01529                         }
01530                 }
01531                 
01532                 // HACK: Compatibility with extensions still using SkinTemplateToolboxEnd
01533                 $hookContents = null;
01534                 if ( isset( $boxes['TOOLBOX'] ) ) {
01535                         ob_start();
01536                         // We pass an extra 'true' at the end so extensions using BaseTemplateToolbox
01537                         // can abort and avoid outputting double toolbox links
01538                         wfRunHooks( 'SkinTemplateToolboxEnd', array( &$this, true ) );
01539                         $hookContents = ob_get_contents();
01540                         ob_end_clean();
01541                         if ( !trim( $hookContents ) ) {
01542                                 $hookContents = null;
01543                         }
01544                 }
01545                 // END hack
01546                 
01547                 if ( isset( $options['htmlOnly'] ) && $options['htmlOnly'] === true ) {
01548                         foreach ( $boxes as $boxName => $box ) {
01549                                 if ( is_array( $box['content'] ) ) {
01550                                         $content = "<ul>";
01551                                         foreach ( $box['content'] as $key => $val ) {
01552                                                 $content .= "\n " . $this->makeListItem( $key, $val );
01553                                         }
01554                                         // HACK, shove the toolbox end onto the toolbox if we're rendering itself
01555                                         if ( $hookContents ) {
01556                                                 $content .= "\n $hookContents"; 
01557                                         }
01558                                         // END hack
01559                                         $content .= "\n</ul>\n";
01560                                         $boxes[$boxName]['content'] = $content;
01561                                 }
01562                         }
01563                 } else {
01564                         if ( $hookContents ) {
01565                                 $boxes['TOOLBOXEND'] = array(
01566                                         'id'        => "p-toolboxend",
01567                                         'header'    => $boxes['TOOLBOX']['header'],
01568                                         'generated' => false,
01569                                         'content'   => "<ul>{$hookContents}</ul>",
01570                                 );
01571                                 // HACK: Make sure that TOOLBOXEND is sorted next to TOOLBOX
01572                                 $boxes2 = array();
01573                                 foreach ( $boxes as $key => $box ) {
01574                                         if ( $key === 'TOOLBOXEND' ) {
01575                                                 continue;
01576                                         }
01577                                         $boxes2[$key] = $box;
01578                                         if ( $key === 'TOOLBOX' ) {
01579                                                 $boxes2['TOOLBOXEND'] = $boxes['TOOLBOXEND'];
01580                                         }
01581                                 }
01582                                 $boxes = $boxes2;
01583                                 // END hack
01584                         }
01585                 }
01586                 
01587                 return $boxes;
01588         }
01589 
01615         function makeLink( $key, $item, $options = array() ) {
01616                 if ( isset( $item['text'] ) ) {
01617                         $text = $item['text'];
01618                 } else {
01619                         $text = $this->translator->translate( isset( $item['msg'] ) ? $item['msg'] : $key );
01620                 }
01621 
01622                 $html = htmlspecialchars( $text );
01623 
01624                 if ( isset( $options['text-wrapper'] ) ) {
01625                         $wrapper = $options['text-wrapper'];
01626                         if ( isset( $wrapper['tag'] ) ) {
01627                                 $wrapper = array( $wrapper );
01628                         }
01629                         while ( count( $wrapper ) > 0 ) {
01630                                 $element = array_pop( $wrapper );
01631                                 $html = Html::rawElement( $element['tag'], isset( $element['attributes'] ) ? $element['attributes'] : null, $html );
01632                         }
01633                 }
01634 
01635                 if ( isset( $item['href'] ) || isset( $options['link-fallback'] ) ) {
01636                         $attrs = $item;
01637                         foreach ( array( 'single-id', 'text', 'msg', 'tooltiponly' ) as $k ) {
01638                                 unset( $attrs[$k] );
01639                         }
01640 
01641                         if ( isset( $item['id'] ) && !isset( $item['single-id'] ) ) {
01642                                 $item['single-id'] = $item['id'];
01643                         }
01644                         if ( isset( $item['single-id'] ) ) {
01645                                 if ( isset( $item['tooltiponly'] ) && $item['tooltiponly'] ) {
01646                                         $title = Linker::titleAttrib( $item['single-id'] );
01647                                         if ( $title !== false ) {
01648                                                 $attrs['title'] = $title;
01649                                         }
01650                                 } else {
01651                                         $tip = Linker::tooltipAndAccesskeyAttribs( $item['single-id'] );
01652                                         if ( isset( $tip['title'] ) && $tip['title'] !== false ) {
01653                                                 $attrs['title'] = $tip['title'];
01654                                         }
01655                                         if ( isset( $tip['accesskey'] ) && $tip['accesskey'] !== false ) {
01656                                                 $attrs['accesskey'] = $tip['accesskey'];
01657                                         }
01658                                 }
01659                         }
01660                         if ( isset( $options['link-class'] ) ) {
01661                                 if ( isset( $attrs['class'] ) ) {
01662                                         $attrs['class'] .= " {$options['link-class']}";
01663                                 } else {
01664                                         $attrs['class'] = $options['link-class'];
01665                                 }
01666                         }
01667                         $html = Html::rawElement( isset( $attrs['href'] ) ? 'a' : $options['link-fallback'], $attrs, $html );
01668                 }
01669 
01670                 return $html;
01671         }
01672 
01693         function makeListItem( $key, $item, $options = array() ) {
01694                 if ( isset( $item['links'] ) ) {
01695                         $html = '';
01696                         foreach ( $item['links'] as $linkKey => $link ) {
01697                                 $html .= $this->makeLink( $linkKey, $link, $options );
01698                         }
01699                 } else {
01700                         $link = $item;
01701                         // These keys are used by makeListItem and shouldn't be passed on to the link
01702                         foreach ( array( 'id', 'class', 'active', 'tag' ) as $k ) {
01703                                 unset( $link[$k] );
01704                         }
01705                         if ( isset( $item['id'] ) ) {
01706                                 // The id goes on the <li> not on the <a> for single links
01707                                 // but makeSidebarLink still needs to know what id to use when
01708                                 // generating tooltips and accesskeys.
01709                                 $link['single-id'] = $item['id'];
01710                         }
01711                         $html = $this->makeLink( $key, $link, $options );
01712                 }
01713 
01714                 $attrs = array();
01715                 foreach ( array( 'id', 'class' ) as $attr ) {
01716                         if ( isset( $item[$attr] ) ) {
01717                                 $attrs[$attr] = $item[$attr];
01718                         }
01719                 }
01720                 if ( isset( $item['active'] ) && $item['active'] ) {
01721                         if ( !isset( $attrs['class'] ) ) {
01722                                 $attrs['class'] = '';
01723                         }
01724                         $attrs['class'] .= ' active';
01725                         $attrs['class'] = trim( $attrs['class'] );
01726                 }
01727                 return Html::rawElement( isset( $options['tag'] ) ? $options['tag'] : 'li', $attrs, $html );
01728         }
01729 
01730         function makeSearchInput( $attrs = array() ) {
01731                 $realAttrs = array(
01732                         'type' => 'search',
01733                         'name' => 'search',
01734                         'value' => isset( $this->data['search'] ) ? $this->data['search'] : '',
01735                 );
01736                 $realAttrs = array_merge( $realAttrs, Linker::tooltipAndAccesskeyAttribs( 'search' ), $attrs );
01737                 return Html::element( 'input', $realAttrs );
01738         }
01739 
01740         function makeSearchButton( $mode, $attrs = array() ) {
01741                 switch( $mode ) {
01742                         case 'go':
01743                         case 'fulltext':
01744                                 $realAttrs = array(
01745                                         'type' => 'submit',
01746                                         'name' => $mode,
01747                                         'value' => $this->translator->translate(
01748                                                 $mode == 'go' ? 'searcharticle' : 'searchbutton' ),
01749                                 );
01750                                 $realAttrs = array_merge(
01751                                         $realAttrs,
01752                                         Linker::tooltipAndAccesskeyAttribs( "search-$mode" ),
01753                                         $attrs
01754                                 );
01755                                 return Html::element( 'input', $realAttrs );
01756                         case 'image':
01757                                 $buttonAttrs = array(
01758                                         'type' => 'submit',
01759                                         'name' => 'button',
01760                                 );
01761                                 $buttonAttrs = array_merge(
01762                                         $buttonAttrs,
01763                                         Linker::tooltipAndAccesskeyAttribs( 'search-fulltext' ),
01764                                         $attrs
01765                                 );
01766                                 unset( $buttonAttrs['src'] );
01767                                 unset( $buttonAttrs['alt'] );
01768                                 $imgAttrs = array(
01769                                         'src' => $attrs['src'],
01770                                         'alt' => isset( $attrs['alt'] )
01771                                                 ? $attrs['alt']
01772                                                 : $this->translator->translate( 'searchbutton' ),
01773                                 );
01774                                 return Html::rawElement( 'button', $buttonAttrs, Html::element( 'img', $imgAttrs ) );
01775                         default:
01776                                 throw new MWException( 'Unknown mode passed to BaseTemplate::makeSearchButton' );
01777                 }
01778         }
01779 
01787         function getFooterLinks( $option = null ) {
01788                 $footerlinks = $this->data['footerlinks'];
01789 
01790                 // Reduce footer links down to only those which are being used
01791                 $validFooterLinks = array();
01792                 foreach( $footerlinks as $category => $links ) {
01793                         $validFooterLinks[$category] = array();
01794                         foreach( $links as $link ) {
01795                                 if( isset( $this->data[$link] ) && $this->data[$link] ) {
01796                                         $validFooterLinks[$category][] = $link;
01797                                 }
01798                         }
01799                         if ( count( $validFooterLinks[$category] ) <= 0 ) {
01800                                 unset( $validFooterLinks[$category] );
01801                         }
01802                 }
01803 
01804                 if ( $option == 'flat' ) {
01805                         // fold footerlinks into a single array using a bit of trickery
01806                         $validFooterLinks = call_user_func_array(
01807                                 'array_merge',
01808                                 array_values( $validFooterLinks )
01809                         );
01810                 }
01811 
01812                 return $validFooterLinks;
01813         }
01814 
01825         function getFooterIcons( $option = null ) {
01826                 // Generate additional footer icons
01827                 $footericons = $this->data['footericons'];
01828 
01829                 if ( $option == 'icononly' ) {
01830                         // Unset any icons which don't have an image
01831                         foreach ( $footericons as &$footerIconsBlock ) {
01832                                 foreach ( $footerIconsBlock as $footerIconKey => $footerIcon ) {
01833                                         if ( !is_string( $footerIcon ) && !isset( $footerIcon['src'] ) ) {
01834                                                 unset( $footerIconsBlock[$footerIconKey] );
01835                                         }
01836                                 }
01837                         }
01838                         // Redo removal of any empty blocks
01839                         foreach ( $footericons as $footerIconsKey => &$footerIconsBlock ) {
01840                                 if ( count( $footerIconsBlock ) <= 0 ) {
01841                                         unset( $footericons[$footerIconsKey] );
01842                                 }
01843                         }
01844                 } elseif ( $option == 'nocopyright' ) {
01845                         unset( $footericons['copyright']['copyright'] );
01846                         if ( count( $footericons['copyright'] ) <= 0 ) {
01847                                 unset( $footericons['copyright'] );
01848                         }
01849                 }
01850 
01851                 return $footericons;
01852         }
01853 
01859         function printTrail() { ?>
01860 <?php $this->html('bottomscripts'); /* JS call to runBodyOnloadHook */ ?>
01861 <?php $this->html('reporttime') ?>
01862 <?php if ( $this->data['debug'] ): ?>
01863 <!-- Debug output:
01864 <?php $this->text( 'debug' ); ?>
01865 
01866 -->
01867 <?php endif;
01868         }
01869 
01870 }
01871