Follow up r78101.
[lhc/web/wiklou.git] / includes / SkinTemplate.php
index cbe689f..afdd41c 100644 (file)
@@ -1,21 +1,28 @@
 <?php
-if ( ! defined( 'MEDIAWIKI' ) )
-       die( 1 );
+/**
+ * Base class for template-based skins
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
 
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-# http://www.gnu.org/copyleft/gpl.html
+if ( !defined( 'MEDIAWIKI' ) ) {
+       die( 1 );
+}
 
 /**
  * Wrapper object for MediaWiki's localization functions,
@@ -101,8 +108,7 @@ class SkinTemplate extends Skin {
         * @param $out OutputPage
         */
        function setupSkinUserCss( OutputPage $out ){
-               $out->addStyle( 'common/shared.css', 'screen' );
-               $out->addStyle( 'common/commonPrint.css', 'print' );
+               $out->addModuleStyles( array( 'mediawiki.legacy.shared', 'mediawiki.legacy.commonPrint' ) );
        }
 
        /**
@@ -110,7 +116,7 @@ class SkinTemplate extends Skin {
         * and eventually it spits out some HTML. Should have interface
         * roughly equivalent to PHPTAL 0.7.
         *
-        * @param $callback string (or file)
+        * @param $classname string (or file)
         * @param $repository string: subdirectory where we keep template files
         * @param $cache_dir string
         * @return object
@@ -127,16 +133,19 @@ class SkinTemplate extends Skin {
         */
        function outputPage( OutputPage $out ) {
                global $wgArticle, $wgUser, $wgLang, $wgContLang;
-               global $wgScript, $wgStylePath, $wgContLanguageCode;
+               global $wgScript, $wgStylePath, $wgLanguageCode;
                global $wgMimeType, $wgJsMimeType, $wgOutputEncoding, $wgRequest;
                global $wgXhtmlDefaultNamespace, $wgXhtmlNamespaces, $wgHtml5Version;
                global $wgDisableCounters, $wgLogo, $wgHideInterlanguageLinks;
                global $wgMaxCredits, $wgShowCreditsIfMax;
                global $wgPageShowWatchingUsers;
                global $wgUseTrackbacks, $wgUseSiteJs, $wgDebugComments;
-               global $wgArticlePath, $wgScriptPath, $wgServer;
+               global $wgArticlePath, $wgScriptPath, $wgServer, $wgProfiler;
 
                wfProfileIn( __METHOD__ );
+               if ( is_object( $wgProfiler ) ) {
+                       $wgProfiler->setTemplated( true );
+               }
 
                $oldid = $wgRequest->getVal( 'oldid' );
                $diff = $wgRequest->getVal( 'diff' );
@@ -209,7 +218,7 @@ class SkinTemplate extends Skin {
                        $tpl->setRef( 'xhtmldefaultnamespace', $wgXhtmlDefaultNamespace );
                        $tpl->set( 'xhtmlnamespaces', $wgXhtmlNamespaces );
                        $tpl->set( 'html5version', $wgHtml5Version );
-                       $tpl->set( 'headlinks', $out->getHeadLinks() );
+                       $tpl->set( 'headlinks', $out->getHeadLinks( $this ) );
                        $tpl->set( 'csslinks', $out->buildCssLinks() );
 
                        if( $wgUseTrackbacks && $out->isArticleRelated() ) {
@@ -244,13 +253,13 @@ class SkinTemplate extends Skin {
                $subpagestr = $this->subPageSubtitle();
                $tpl->set(
                        'subtitle', !empty( $subpagestr ) ?
-                       '<span class="subpages">'.$subpagestr.'</span>'.$out->getSubtitle() :
+                       '<span class="subpages">' . $subpagestr . '</span>' . $out->getSubtitle() :
                        $out->getSubtitle()
                );
                $undelete = $this->getUndeleteLink();
                $tpl->set(
                        'undelete', !empty( $undelete ) ?
-                       '<span class="subpages">'.$undelete.'</span>' :
+                       '<span class="subpages">' . $undelete . '</span>' :
                        ''
                );
 
@@ -280,11 +289,11 @@ class SkinTemplate extends Skin {
                $tpl->setRef( 'loggedin', $this->loggedin );
                $tpl->set( 'notspecialpage', $this->mTitle->getNamespace() != NS_SPECIAL );
                /* XXX currently unused, might get useful later
-               $tpl->set( "editable", ($this->mTitle->getNamespace() != NS_SPECIAL ) );
-               $tpl->set( "exists", $this->mTitle->getArticleID() != 0 );
-               $tpl->set( "watch", $this->mTitle->userIsWatching() ? "unwatch" : "watch" );
-               $tpl->set( "protect", count($this->mTitle->isProtected()) ? "unprotect" : "protect" );
-               $tpl->set( "helppage", wfMsg('helppage'));
+               $tpl->set( 'editable', ( $this->mTitle->getNamespace() != NS_SPECIAL ) );
+               $tpl->set( 'exists', $this->mTitle->getArticleID() != 0 );
+               $tpl->set( 'watch', $this->mTitle->userIsWatching() ? 'unwatch' : 'watch' );
+               $tpl->set( 'protect', count( $this->mTitle->isProtected() ) ? 'unprotect' : 'protect' );
+               $tpl->set( 'helppage', wfMsg( 'helppage' ) );
                */
                $tpl->set( 'searchaction', $this->escapeSearchLink() );
                $tpl->set( 'searchtitle', SpecialPage::getTitleFor( 'Search' )->getPrefixedDBKey() );
@@ -294,11 +303,13 @@ class SkinTemplate extends Skin {
                $tpl->setRef( 'scriptpath', $wgScriptPath );
                $tpl->setRef( 'serverurl', $wgServer );
                $tpl->setRef( 'logopath', $wgLogo );
-               $tpl->setRef( 'lang', $wgContLanguageCode );
-               $tpl->set( 'dir', $wgContLang->getDir() );
-               $tpl->set( 'rtl', $wgContLang->isRTL() );
+
+               $lang = wfUILang();
+               $tpl->set( 'lang', $lang->getCode() );
+               $tpl->set( 'dir', $lang->getDir() );
+               $tpl->set( 'rtl', $lang->isRTL() );
+
                $tpl->set( 'capitalizeallnouns', $wgLang->capitalizeAllNouns() ? ' capitalize-all-nouns' : '' );
-               $tpl->set( 'langname', $wgContLang->getLanguageName( $wgContLanguageCode ) );
                $tpl->set( 'showjumplinks', $wgUser->getOption( 'showjumplinks' ) );
                $tpl->set( 'username', $wgUser->isAnon() ? null : $this->username );
                $tpl->setRef( 'userpage', $this->userpage );
@@ -308,72 +319,29 @@ class SkinTemplate extends Skin {
                // Users can have their language set differently than the
                // content of the wiki. For these users, tell the web browser
                // that interface elements are in a different language.
-               $tpl->set( 'userlangattributes', '');
-               $tpl->set( 'specialpageattributes', '');
+               $tpl->set( 'userlangattributes', '' );
+               $tpl->set( 'specialpageattributes', '' );
 
                $lang = $wgLang->getCode();
                $dir  = $wgLang->getDir();
                if ( $lang !== $wgContLang->getCode() || $dir !== $wgContLang->getDir() ) {
-                       $attrs = "lang='$lang' xml:lang='$lang' dir='$dir'";
+                       $attrs = " lang='$lang' dir='$dir'";
 
                        $tpl->set( 'userlangattributes', $attrs );
 
                        // The content of SpecialPages should be presented in the
                        // user's language. Content of regular pages should not be touched.
-                       if($this->mTitle->isSpecialPage()) {
+                       if( $this->mTitle->isSpecialPage() ) {
                                $tpl->set( 'specialpageattributes', $attrs );
                        }
                }
 
-               $newtalks = $wgUser->getNewMessageLinks();
-
-               if( count( $newtalks ) == 1 && $newtalks[0]['wiki'] === wfWikiID() ) {
-                       $usertitle = $this->mUser->getUserPage();
-                       $usertalktitle = $usertitle->getTalkPage();
-
-                       if( !$usertalktitle->equals( $this->mTitle ) ) {
-                               $newmessageslink = $this->link(
-                                       $usertalktitle,
-                                       wfMsgHtml( 'newmessageslink' ),
-                                       array(),
-                                       array( 'redirect' => 'no' ),
-                                       array( 'known', 'noclasses' )
-                               );
-
-                               $newmessagesdifflink = $this->link(
-                                       $usertalktitle,
-                                       wfMsgHtml( 'newmessagesdifflink' ),
-                                       array(),
-                                       array( 'diff' => 'cur' ),
-                                       array( 'known', 'noclasses' )
-                               );
+               $newtalks = $this->getNewtalks();
 
-                               $ntl = wfMsg(
-                                       'youhavenewmessages',
-                                       $newmessageslink,
-                                       $newmessagesdifflink
-                               );
-                               # Disable Cache
-                               $out->setSquidMaxage( 0 );
-                       }
-               } else if( count( $newtalks ) ) {
-                       // _>" " for BC <= 1.16
-                       $sep = str_replace( '_', ' ', wfMsgHtml( 'newtalkseparator' ) );
-                       $msgs = array();
-                       foreach( $newtalks as $newtalk ) {
-                               $msgs[] = Xml::element('a',
-                                       array( 'href' => $newtalk['link'] ), $newtalk['wiki'] );
-                       }
-                       $parts = implode( $sep, $msgs );
-                       $ntl = wfMsgHtml( 'youhavenewmessagesmulti', $parts );
-                       $out->setSquidMaxage( 0 );
-               } else {
-                       $ntl = '';
-               }
                wfProfileOut( __METHOD__ . '-stuff2' );
 
                wfProfileIn( __METHOD__ . '-stuff3' );
-               $tpl->setRef( 'newtalk', $ntl );
+               $tpl->setRef( 'newtalk', $newtalks );
                $tpl->setRef( 'skin', $this );
                $tpl->set( 'logo', $this->logoText() );
                if ( $out->isArticle() and ( !isset( $oldid ) or isset( $diff ) ) and
@@ -391,7 +359,6 @@ class SkinTemplate extends Skin {
 
                        if( $wgPageShowWatchingUsers ) {
                                $dbr = wfGetDB( DB_SLAVE );
-                               $watchlist = $dbr->tableName( 'watchlist' );
                                $res = $dbr->select( 'watchlist',
                                        array( 'COUNT(*) AS n' ),
                                        array( 'wl_title' => $dbr->strencode( $this->mTitle->getDBkey() ), 'wl_namespace' => $this->mTitle->getNamespace() ),
@@ -445,6 +412,40 @@ class SkinTemplate extends Skin {
                $tpl->set( 'privacy', $this->privacyLink() );
                $tpl->set( 'about', $this->aboutLink() );
 
+               $tpl->set( 'footerlinks', array(
+                       'info' => array(
+                               'lastmod',
+                               'viewcount',
+                               'numberofwatchingusers',
+                               'credits',
+                               'copyright',
+                       ),
+                       'places' => array(
+                               'privacy',
+                               'about',
+                               'disclaimer',
+                       ),
+               ) );
+
+               global $wgFooterIcons;
+               $tpl->set( 'footericons', $wgFooterIcons );
+               foreach ( $tpl->data['footericons'] as $footerIconsKey => &$footerIconsBlock ) {
+                       if ( count( $footerIconsBlock ) > 0 ) {
+                               foreach ( $footerIconsBlock as &$footerIcon ) {
+                                       if ( isset( $footerIcon['src'] ) ) {
+                                               if ( !isset( $footerIcon['width'] ) ) {
+                                                       $footerIcon['width'] = 88;
+                                               }
+                                               if ( !isset( $footerIcon['height'] ) ) {
+                                                       $footerIcon['height'] = 31;
+                                               }
+                                       }
+                               }
+                       } else {
+                               unset( $tpl->data['footericons'][$footerIconsKey] );
+                       }
+               }
+
                if ( $wgDebugComments ) {
                        $tpl->setRef( 'debug', $out->mDebugtext );
                } else {
@@ -453,9 +454,14 @@ class SkinTemplate extends Skin {
 
                $tpl->set( 'reporttime', wfReportTime() );
                $tpl->set( 'sitenotice', wfGetSiteNotice() );
-               $tpl->set( 'bottomscripts', $this->bottomScripts() );
+               $tpl->set( 'bottomscripts', $this->bottomScripts( $out ) );
 
                $printfooter = "<div class=\"printfooter\">\n" . $this->printSource() . "</div>\n";
+               global $wgBetterDirectionality;
+               if ( $wgBetterDirectionality ) {
+                       $realBodyAttribs = array( 'lang' => $wgLanguageCode, 'dir' => $wgContLang->getDir() );
+                       $out->mBodytext = Html::rawElement( 'div', $realBodyAttribs, $out->mBodytext );
+               }
                $out->mBodytext .= $printfooter . $this->generateDebugHTML();
                $tpl->setRef( 'bodytext', $out->mBodytext );
 
@@ -473,6 +479,7 @@ class SkinTemplate extends Skin {
                                                'href' => $nt->getFullURL(),
                                                'text' => ( $wgContLang->getLanguageName( $nt->getInterwiki() ) != '' ?
                                                                        $wgContLang->getLanguageName( $nt->getInterwiki() ) : $l ),
+                                               'title' => $nt->getText(),
                                                'class' => $class
                                        );
                                }
@@ -491,14 +498,6 @@ class SkinTemplate extends Skin {
                $content_actions = $this->buildContentActionUrls();
                $tpl->setRef( 'content_actions', $content_actions );
 
-               // XXX: attach this from javascript, same with section editing
-               if( $this->iseditable && $wgUser->getOption( 'editondblclick' ) ){
-                       $encEditUrl = Xml::escapeJsString( $this->mTitle->getLocalUrl( $this->editUrlOptions() ) );
-                       $tpl->set( 'body_ondblclick', 'document.location = "' . $encEditUrl . '";' );
-               } else {
-                       $tpl->set( 'body_ondblclick', false );
-               }
-               $tpl->set( 'body_onload', false );
                $tpl->set( 'sidebar', $this->buildSidebar() );
                $tpl->set( 'nav_urls', $this->buildNavUrls() );
 
@@ -534,7 +533,7 @@ class SkinTemplate extends Skin {
         * an error object of the appropriate type.
         * For the base class, assume strings all around.
         *
-        * @param mixed $str
+        * @param $str Mixed
         * @private
         */
        function printOrError( $str ) {
@@ -558,8 +557,9 @@ class SkinTemplate extends Skin {
                $page = $wgRequest->getVal( 'returnto', $this->thisurl );
                $query = $wgRequest->getVal( 'returntoquery', $this->thisquery );
                $returnto = "returnto=$page";
-               if( $this->thisquery != '' )
+               if( $this->thisquery != '' ) {
                        $returnto .= "&returntoquery=$query";
+               }
                if( $this->loggedin ) {
                        $personal_urls['userpage'] = array(
                                'text' => $this->username,
@@ -621,6 +621,21 @@ class SkinTemplate extends Skin {
                        $loginlink = $wgUser->isAllowed( 'createaccount' )
                                ? 'nav-login-createaccount'
                                : 'login';
+
+                       # anonlogin & login are the same
+                       $login_url = array(
+                               'text' => wfMsg( $loginlink ),
+                               'href' => self::makeSpecialUrl( 'Userlogin', $returnto ),
+                               'active' => $title->isSpecial( 'Userlogin' )
+                       );
+                       global $wgProto, $wgSecureLogin;
+                       if( $wgProto === 'http' && $wgSecureLogin ) {
+                               $title = SpecialPage::getTitleFor( 'Userlogin' );
+                               $https_url = preg_replace( '/^http:/', 'https:', $title->getFullURL() );
+                               $login_url['href']  = $https_url;
+                               $login_url['class'] = 'link-https';  # FIXME class depends on skin
+                       }
+
                        if( $this->showIPinHeader() ) {
                                $href = &$this->userpageUrlDetails['href'];
                                $personal_urls['anonuserpage'] = array(
@@ -637,17 +652,9 @@ class SkinTemplate extends Skin {
                                        'class' => $usertalkUrlDetails['exists'] ? false : 'new',
                                        'active' => ( $pageurl == $href )
                                );
-                               $personal_urls['anonlogin'] = array(
-                                       'text' => wfMsg( $loginlink ),
-                                       'href' => self::makeSpecialUrl( 'Userlogin', $returnto ),
-                                       'active' => $title->isSpecial( 'Userlogin' )
-                               );
+                               $personal_urls['anonlogin'] = $login_url;
                        } else {
-                               $personal_urls['login'] = array(
-                                       'text' => wfMsg( $loginlink ),
-                                       'href' => self::makeSpecialUrl( 'Userlogin', $returnto ),
-                                       'active' => $title->isSpecial( 'Userlogin' )
-                               );
+                               $personal_urls['login'] = $login_url;
                        }
                }
 
@@ -694,7 +701,7 @@ class SkinTemplate extends Skin {
                self::checkTitle( $title, $name );
                return array(
                        'href' => $title->getLocalURL( $urlaction ),
-                       'exists' => $title->getArticleID() != 0 ? true : false
+                       'exists' => $title->getArticleID() != 0,
                );
        }
 
@@ -704,7 +711,7 @@ class SkinTemplate extends Skin {
                self::checkTitle( $title, $name );
                return array(
                        'href' => $title->getLocalURL( $urlaction ),
-                       'exists' => $title->getArticleID() != 0 ? true : false
+                       'exists' => $title->getArticleID() != 0,
                );
        }
 
@@ -751,7 +758,7 @@ class SkinTemplate extends Skin {
                                $istalkclass = $istalk?' istalk':'';
                                $content_actions['edit'] = array(
                                        'class' => ( ( ( $action == 'edit' or $action == 'submit' ) and $section != 'new' ) ? 'selected' : '' ) . $istalkclass,
-                                       'text' => $this->mTitle->exists()
+                                       'text' => ( $this->mTitle->exists() || ( $this->mTitle->getNamespace() == NS_MEDIAWIKI && !wfEmptyMsg( $this->mTitle->getText() ) ) )
                                                ? wfMsg( 'edit' )
                                                : wfMsg( 'create' ),
                                        'href' => $this->mTitle->getLocalUrl( $this->editUrlOptions() )
@@ -767,7 +774,7 @@ class SkinTemplate extends Skin {
                                                );
                                        }
                                }
-                       } elseif ( $this->mTitle->isKnown() ) {
+                       } elseif ( $this->mTitle->hasSourceText() ) {
                                $content_actions['viewsource'] = array(
                                        'class' => ($action == 'edit') ? 'selected' : false,
                                        'text' => wfMsg( 'viewsource' ),
@@ -821,7 +828,8 @@ class SkinTemplate extends Skin {
                        } else {
                                //article doesn't exist or is deleted
                                if( $wgUser->isAllowed( 'deletedhistory' ) && $wgUser->isAllowed( 'deletedtext' ) ) {
-                                       if( $n = $this->mTitle->isDeleted() ) {
+                                       $n = $this->mTitle->isDeleted();
+                                       if( $n ) {
                                                $undelTitle = SpecialPage::getTitleFor( 'Undelete' );
                                                $content_actions['undelete'] = array(
                                                        'class' => false,
@@ -915,7 +923,7 @@ class SkinTemplate extends Skin {
         */
        function buildNavUrls() {
                global $wgUseTrackbacks, $wgOut, $wgUser, $wgRequest;
-               global $wgEnableUploads, $wgUploadNavigationUrl;
+               global $wgUploadNavigationUrl;
 
                wfProfileIn( __METHOD__ );
 
@@ -925,7 +933,7 @@ class SkinTemplate extends Skin {
                $nav_urls['mainpage'] = array( 'href' => self::makeMainPageUrl() );
                if( $wgUploadNavigationUrl ) {
                        $nav_urls['upload'] = array( 'href' => $wgUploadNavigationUrl );
-               } elseif( $wgEnableUploads && $wgUser->isAllowed( 'upload' ) ) {
+               } elseif( UploadBase::isEnabled() && UploadBase::isAllowed( $wgUser ) === true ) {
                        $nav_urls['upload'] = array( 'href' => self::makeSpecialUrl( 'Upload' ) );
                } else {
                        $nav_urls['upload'] = false;
@@ -978,8 +986,9 @@ class SkinTemplate extends Skin {
                }
 
                if( $this->mTitle->getNamespace() == NS_USER || $this->mTitle->getNamespace() == NS_USER_TALK ) {
-                       $id = User::idFromName( $this->mTitle->getText() );
-                       $ip = User::isIP( $this->mTitle->getText() );
+                       $rootUser = strtok( $this->mTitle->getText(), '/' );
+                       $id = User::idFromName( $rootUser );
+                       $ip = User::isIP( $rootUser );
                } else {
                        $id = 0;
                        $ip = false;
@@ -987,7 +996,7 @@ class SkinTemplate extends Skin {
 
                if( $id || $ip ) { # both anons and non-anons have contribs list
                        $nav_urls['contributions'] = array(
-                               'href' => self::makeSpecialUrlSubpage( 'Contributions', $this->mTitle->getText() )
+                               'href' => self::makeSpecialUrlSubpage( 'Contributions', $rootUser )
                        );
 
                        if( $id ) {
@@ -995,7 +1004,7 @@ class SkinTemplate extends Skin {
                                $nav_urls['log'] = array(
                                        'href' => $logPage->getLocalUrl(
                                                array(
-                                                       'user' => $this->mTitle->getText()
+                                                       'user' => $rootUser
                                                )
                                        )
                                );
@@ -1005,7 +1014,7 @@ class SkinTemplate extends Skin {
 
                        if ( $wgUser->isAllowed( 'block' ) ) {
                                $nav_urls['blockip'] = array(
-                                       'href' => self::makeSpecialUrlSubpage( 'Blockip', $this->mTitle->getText() )
+                                       'href' => self::makeSpecialUrlSubpage( 'Blockip', $rootUser )
                                );
                        } else {
                                $nav_urls['blockip'] = false;
@@ -1018,7 +1027,7 @@ class SkinTemplate extends Skin {
                $nav_urls['emailuser'] = false;
                if( $this->showEmailUser( $id ) ) {
                        $nav_urls['emailuser'] = array(
-                               'href' => self::makeSpecialUrlSubpage( 'Emailuser', $this->mTitle->getText() )
+                               'href' => self::makeSpecialUrlSubpage( 'Emailuser', $rootUser )
                        );
                }
                wfProfileOut( __METHOD__ );
@@ -1180,3 +1189,303 @@ abstract class QuickTemplate {
                return ( $msg != '-' ) && ( $msg != '' ); # ????
        }
 }
+
+/**
+ * New base template for a skin's template extended from QuickTemplate
+ * this class features helper methods that provide common ways of interacting
+ * with the data stored in the QuickTemplate
+ */
+abstract class BaseTemplate extends QuickTemplate {
+
+       /**
+        * Create an array of common toolbox items from the data in the quicktemplate
+        * stored by SkinTemplate.
+        * The resulting array is built acording to a format intended to be passed
+        * through makeListItem to generate the html.
+        */
+       function getToolbox() {
+               wfProfileIn( __METHOD__ );
+
+               $toolbox = array();
+               if ( $this->data['notspecialpage'] ) {
+                       $toolbox['whatlinkshere'] = $this->data['nav_urls']['whatlinkshere'];
+                       $toolbox['whatlinkshere']['id'] = 't-whatlinkshere';
+                       if ( $this->data['nav_urls']['recentchangeslinked'] ) {
+                               $toolbox['recentchangeslinked'] = $this->data['nav_urls']['recentchangeslinked'];
+                               $toolbox['recentchangeslinked']['msg'] = 'recentchangeslinked-toolbox';
+                               $toolbox['recentchangeslinked']['id'] = 't-recentchangeslinked';
+                       }
+               }
+               if( isset( $this->data['nav_urls']['trackbacklink'] ) && $this->data['nav_urls']['trackbacklink'] ) {
+                       $toolbox['trackbacklink'] = $this->data['nav_urls']['trackbacklink'];
+                       $toolbox['trackbacklink']['id'] = 't-trackbacklink';
+               }
+               if ( $this->data['feeds'] ) {
+                       $toolbox['feeds']['id'] = 'feedlinks';
+                       $toolbox['feeds']['links'] = array();
+                       foreach ( $this->data['feeds'] as $key => $feed ) {
+                               $toolbox['feeds']['links'][$key] = $feed;
+                               $toolbox['feeds']['links'][$key]['id'] = "feed-$key";
+                               $toolbox['feeds']['links'][$key]['rel'] = 'alternate';
+                               $toolbox['feeds']['links'][$key]['type'] = "application/{$key}+xml";
+                               $toolbox['feeds']['links'][$key]['class'] = 'feedlink';
+                       }
+               }
+               foreach ( array( 'contributions', 'log', 'blockip', 'emailuser', 'upload', 'specialpages' ) as $special ) {
+                       if ( $this->data['nav_urls'][$special] ) {
+                               $toolbox[$special] = $this->data['nav_urls'][$special];
+                               $toolbox[$special]['id'] = "t-$special";
+                       }
+               }
+               if ( !empty( $this->data['nav_urls']['print']['href'] ) ) {
+                       $toolbox['print'] = $this->data['nav_urls']['print'];
+                       $toolbox['print']['rel'] = 'alternate';
+                       $toolbox['print']['msg'] = 'printableversion';
+               }
+               if ( !empty( $this->data['nav_urls']['permalink']['href'] ) ) {
+                       $toolbox['permalink'] = $this->data['nav_urls']['permalink'];
+                       $toolbox['permalink']['id'] = 't-permalink';
+               } elseif ( $this->data['nav_urls']['permalink']['href'] === '' ) {
+                       $toolbox['permalink'] = $this->data['nav_urls']['permalink'];
+                       unset( $toolbox['permalink']['href'] );
+                       $toolbox['ispermalink']['tooltiponly'] = true;
+                       $toolbox['ispermalink']['id'] = 't-ispermalink';
+                       $toolbox['ispermalink']['msg'] = 'permalink';
+               }
+               wfRunHooks( 'BaseTemplateToolbox', array( &$this, &$toolbox ) );
+               wfProfileOut( __METHOD__ );
+               return $toolbox;
+       }
+
+       /**
+        * Makes a link, usually used by makeListItem to generate a link for an item
+        * in a list used in navigation lists, portlets, portals, sidebars, etc...
+        *
+        * $key is a string, usually a key from the list you are generating this link from
+        * $item is an array containing some of a specific set of keys.
+        * The text of the link will be generated either from the contents of the "text"
+        * key in the $item array, if a "msg" key is present a message by that name will
+        * be used, and if neither of those are set the $key will be used as a message name.
+        * If a "href" key is not present makeLink will just output htmlescaped text.
+        * The href, id, class, rel, and type keys are used as attributes for the link if present.
+        * If an "id" or "single-id" (if you don't want the actual id to be output on the link)
+        * is present it will be used to generate a tooltip and accesskey for the link.
+        * If you don't want an accesskey, set $item['tooltiponly'] = true;
+        */
+       function makeLink( $key, $item ) {
+               if ( isset( $item['text'] ) ) {
+                       $text = $item['text'];
+               } else {
+                       $text = $this->translator->translate( isset( $item['msg'] ) ? $item['msg'] : $key );
+               }
+
+               if ( !isset( $item['href'] ) ) {
+                       return htmlspecialchars( $text );
+               }
+
+               $attrs = array();
+               foreach ( array( 'href', 'id', 'class', 'rel', 'type' ) as $attr ) {
+                       if ( isset( $item[$attr] ) ) {
+                               $attrs[$attr] = $item[$attr];
+                       }
+               }
+
+               if ( isset( $item['id'] ) ) {
+                       $item['single-id'] = $item['id'];
+               }
+               if ( isset( $item['single-id'] ) ) {
+                       if ( isset( $item['tooltiponly'] ) && $item['tooltiponly'] ) {
+                               $attrs['title'] = $this->skin->titleAttrib( $item['single-id'] );
+                               if ( $attrs['title'] === false ) {
+                                       unset( $attrs['title'] );
+                               }
+                       } else {
+                               $attrs = array_merge(
+                                       $attrs,
+                                       $this->skin->tooltipAndAccesskeyAttribs( $item['single-id'] )
+                               );
+                       }
+               }
+
+               return Html::element( 'a', $attrs, $text );
+       }
+
+       /**
+        * Generates a list item for a navigation, portlet, portal, sidebar... etc list
+        * $key is a string, usually a key from the list you are generating this link from
+        * $item is an array of list item data containing some of a specific set of keys.
+        * The "id" and "class" keys will be used as attributes for the list item,
+        * if "active" contains a value of true a "active" class will also be appended to class.
+        * If you want something other than a <li> you can pass a tag name such as
+        * "tag" => "span" in the $options array to change the tag used.
+        * link/content data for the list item may come in one of two forms
+        * A "links" key may be used, in which case it should contain an array with
+        * a list of links to include inside the list item, see makeLink for the format
+        * of individual links array items.
+        * Otherwise the relevant keys from the list item $item array will be passed
+        * to makeLink instead. Note however that "id" and "class" are used by the
+        * list item directly so they will not be passed to makeLink
+        * (however the link will still support a tooltip and accesskey from it)
+        * If you need an id or class on a single link you should include a "links"
+        * array with just one link item inside of it.
+        */
+       function makeListItem( $key, $item, $options = array() ) {
+               if ( isset( $item['links'] ) ) {
+                       $html = '';
+                       foreach ( $item['links'] as $linkKey => $link ) {
+                               $html .= $this->makeLink( $linkKey, $link );
+                       }
+               } else {
+                       $link = array();
+                       foreach ( array( 'text', 'msg', 'href', 'rel', 'type', 'tooltiponly' ) as $k ) {
+                               if ( isset( $item[$k] ) ) {
+                                       $link[$k] = $item[$k];
+                               }
+                       }
+                       if ( isset( $item['id'] ) ) {
+                               // The id goes on the <li> not on the <a> for single links
+                               // but makeSidebarLink still needs to know what id to use when
+                               // generating tooltips and accesskeys.
+                               $link['single-id'] = $item['id'];
+                       }
+                       $html = $this->makeLink( $key, $link  );
+               }
+
+               $attrs = array();
+               foreach ( array( 'id', 'class' ) as $attr ) {
+                       if ( isset( $item[$attr] ) ) {
+                               $attrs[$attr] = $item[$attr];
+                       }
+               }
+               if ( isset( $item['active'] ) && $item['active'] ) {
+                       $attrs['class'] .= ' active';
+                       $attrs['class'] = trim( $attrs['class'] );
+               }
+               return Html::rawElement( isset( $options['tag'] ) ? $options['tag'] : 'li', $attrs, $html );
+       }
+
+       function makeSearchInput( $attrs = array() ) {
+               $realAttrs = array(
+                       'type' => 'search',
+                       'name' => 'search',
+                       'value' => isset( $this->data['search'] ) ? $this->data['search'] : '',
+               );
+               $realAttrs = array_merge( $realAttrs, $this->skin->tooltipAndAccesskeyAttribs( 'search' ), $attrs );
+               return Html::element( 'input', $realAttrs );
+       }
+
+       function makeSearchButton( $mode, $attrs = array() ) {
+               switch( $mode ) {
+                       case 'go':
+                       case 'fulltext':
+                               $realAttrs = array(
+                                       'type' => 'submit',
+                                       'name' => $mode,
+                                       'value' => $this->translator->translate( $mode == 'go' ? 'searcharticle' : 'searchbutton' ),
+                               );
+                               $realAttrs = array_merge(
+                                       $realAttrs,
+                                       $this->skin->tooltipAndAccesskeyAttribs( "search-$mode" ),
+                                       $attrs
+                               );
+                               return Html::element( 'input', $realAttrs );
+                       case 'image':
+                               $buttonAttrs = array(
+                                       'type' => 'submit',
+                                       'name' => 'button',
+                               );
+                               $buttonAttrs = array_merge(
+                                       $buttonAttrs,
+                                       $this->skin->tooltipAndAccesskeyAttribs( 'search-fulltext' ),
+                                       $attrs
+                               );
+                               unset( $buttonAttrs['src'] );
+                               unset( $buttonAttrs['alt'] );
+                               $imgAttrs = array(
+                                       'src' => $attrs['src'],
+                                       'alt' => isset( $attrs['alt'] ) ? $attrs['alt'] : $this->translator->translate( 'searchbutton' ),
+                               );
+                               return Html::rawElement( 'button', $buttonAttrs, Html::element( 'img', $imgAttrs ) );
+                       default:
+                               throw new MWException( 'Unknown mode passed to BaseTemplate::makeSearchButton' );
+               }
+       }
+
+       /**
+        * Returns an array of footerlinks trimmed down to only those footer links that
+        * are valid.
+        * If you pass "flat" as an option then the returned array will be a flat array
+        * of footer icons instead of a key/value array of footerlinks arrays broken
+        * up into categories.
+        */
+       function getFooterLinks( $option = null ) {
+               $footerlinks = $this->data['footerlinks'];
+
+               // Reduce footer links down to only those which are being used
+               $validFooterLinks = array();
+               foreach( $footerlinks as $category => $links ) {
+                       $validFooterLinks[$category] = array();
+                       foreach( $links as $link ) {
+                               if( isset( $this->data[$link] ) && $this->data[$link] ) {
+                                       $validFooterLinks[$category][] = $link;
+                               }
+                       }
+                       if ( count( $validFooterLinks[$category] ) <= 0 ) {
+                               unset( $validFooterLinks[$category] );
+                       }
+               }
+
+               if ( $option == 'flat' ) {
+                       // fold footerlinks into a single array using a bit of trickery
+                       $validFooterLinks = call_user_func_array(
+                               'array_merge',
+                               array_values( $validFooterLinks )
+                       );
+               }
+
+               return $validFooterLinks;
+       }
+
+       /**
+        * Returns an array of footer icons filtered down by options relevant to how
+        * the skin wishes to display them.
+        * If you pass "icononly" as the option all footer icons which do not have an
+        * image icon set will be filtered out.
+        * If you pass "nocopyright" then MediaWiki's copyright icon will not be included
+        * in the list of footer icons. This is mostly useful for skins which only
+        * display the text from footericons instead of the images and don't want a
+        * duplicate copyright statement because footerlinks already rendered one.
+        */
+       function getFooterIcons( $option = null ) {
+               // Generate additional footer icons
+               $footericons = $this->data['footericons'];
+
+               if ( $option == 'icononly' ) {
+                       // Unset any icons which don't have an image
+                       foreach ( $footericons as $footerIconsKey => &$footerIconsBlock ) {
+                               foreach ( $footerIconsBlock as $footerIconKey => $footerIcon ) {
+                                       if ( !is_string( $footerIcon ) && !isset( $footerIcon['src'] ) ) {
+                                               unset( $footerIconsBlock[$footerIconKey] );
+                                       }
+                               }
+                       }
+                       // Redo removal of any empty blocks
+                       foreach ( $footericons as $footerIconsKey => &$footerIconsBlock ) {
+                               if ( count( $footerIconsBlock ) <= 0 ) {
+                                       unset( $footericons[$footerIconsKey] );
+                               }
+                       }
+               } elseif ( $option == 'nocopyright' ) {
+                       $footericons = $this->data['footericons'];
+                       unset( $footericons['copyright']['copyright'] );
+                       if ( count( $footericons['copyright'] ) <= 0 ) {
+                               unset( $footericons['copyright'] );
+                       }
+               }
+
+               return $footericons;
+       }
+
+
+}
+