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