follow-up r52858: remove unused "global $wgMessageCache;"
[lhc/web/wiklou.git] / includes / OutputPage.php
index 3862e3f..a05867d 100644 (file)
@@ -35,6 +35,7 @@ class OutputPage {
        var $mParseWarnings = array();
        var $mSquidMaxage = 0;
        var $mRevisionId = null;
+       protected $mTitle = null;
 
        /**
         * An array of stylesheet filenames (relative from skins path), with options
@@ -84,8 +85,15 @@ class OutputPage {
                array_push( $this->mMetatags, array( $name, $val ) );
        }
 
-       function addKeyword( $text ) { array_push( $this->mKeywords, $text ); }
-       function addScript( $script ) { $this->mScripts .= "\t\t".$script; }
+       function addKeyword( $text ) {
+               if( is_array( $text )) {
+                       $this->mKeywords = array_merge( $this->mKeywords, $text );
+               }
+               else {
+                       array_push( $this->mKeywords, $text );
+               }
+       }
+       function addScript( $script ) { $this->mScripts .= "\t" . $script . "\n"; }
        
        function addExtensionStyle( $url ) {
                $linkarr = array( 'rel' => 'stylesheet', 'href' => $url, 'type' => 'text/css' );
@@ -103,7 +111,15 @@ class OutputPage {
                } else {
                        $path =  "{$wgStylePath}/common/{$file}";
                }
-               $this->addScript( "<script type=\"{$wgJsMimeType}\" src=\"$path?$wgStyleVersion\"></script>\n" );
+               $this->addScript( 
+                       Xml::element( 'script', 
+                               array(
+                                       'type' => $wgJsMimeType,
+                                       'src' => "$path?$wgStyleVersion",
+                               ),
+                               '', false
+                       )
+               );      
        }
        
        /**
@@ -112,7 +128,7 @@ class OutputPage {
         */
        function addInlineScript( $script ) {
                global $wgJsMimeType;
-               $this->mScripts .= "<script type=\"$wgJsMimeType\">/*<![CDATA[*/\n$script\n/*]]>*/</script>";
+               $this->mScripts .= "\t\t<script type=\"$wgJsMimeType\">/*<![CDATA[*/\n\t\t$script\n\t\t/*]]>*/</script>\n";
        }
 
        function getScript() {
@@ -166,7 +182,7 @@ class OutputPage {
         *
         * @return bool True iff cache-ok headers was sent.
         */
-       function checkLastModified ( $timestamp ) {
+       function checkLastModified( $timestamp ) {
                global $wgCachePages, $wgCacheEpoch, $wgUser, $wgRequest;
                
                if ( !$timestamp || $timestamp == '19700101000000' ) {
@@ -233,6 +249,7 @@ class OutputPage {
                # Not modified
                # Give a 304 response code and disable body output 
                wfDebug( __METHOD__ . ": NOT MODIFIED, $info\n", false );
+               ini_set('zlib.output_compression', 0);
                $wgRequest->response()->header( "HTTP/1.1 304 Not Modified" );
                $this->sendCacheControl();
                $this->disable();
@@ -310,18 +327,49 @@ class OutputPage {
                }
        }
 
-       public function setHTMLTitle( $name ) { $this->mHTMLtitle = $name; }
+       /**
+        * "HTML title" means the contents of <title>. It is stored as plain, unescaped text and will be run through htmlspecialchars in the skin file.
+        */
+       public function setHTMLTitle( $name ) {
+               $this->mHTMLtitle = $name;
+       }
+
+       /**
+        * "Page title" means the contents of <h1>. It is stored as a valid HTML fragment.
+        * This function allows good tags like <sup> in the <h1> tag, but not bad tags like <script>.
+        * This function automatically sets <title> to the same content as <h1> but with all tags removed.
+        * Bad tags that were escaped in <h1> will still be escaped in <title>, and good tags like <i> will be dropped entirely.
+         */
        public function setPageTitle( $name ) {
                global $wgContLang;
                $name = $wgContLang->convert( $name, true );
-               $this->mPagetitle = $name;
+               # change "<script>foo&bar</script>" to "&lt;script&gt;foo&amp;bar&lt;/script&gt;"
+               # but leave "<i>foobar</i>" alone
+               $nameWithTags = Sanitizer::normalizeCharReferences( Sanitizer::removeHTMLtags( $name ) );
+               $this->mPagetitle = $nameWithTags;
 
                $taction =  $this->getPageTitleActionText();
                if( !empty( $taction ) ) {
                        $name .= ' - '.$taction;
                }
 
-               $this->setHTMLTitle( wfMsg( 'pagetitle', $name ) );
+               # change "<i>foo&amp;bar</i>" to "foo&bar"
+               $this->setHTMLTitle( wfMsg( 'pagetitle', Sanitizer::stripAllTags( $nameWithTags ) ) );
+       }
+       
+       public function setTitle( $t ) {
+               $this->mTitle = $t;
+       }
+       
+       public function getTitle() {
+               if ( $this->mTitle instanceof Title ) {
+                       return $this->mTitle;
+               }
+               else {
+                       wfDebug( __METHOD__ . ' called and $mTitle is null. Return $wgTitle for sanity' );
+                       global $wgTitle;
+                       return $wgTitle;
+               }
        }
 
        public function getHTMLTitle() { return $this->mHTMLtitle; }
@@ -339,6 +387,7 @@ class OutputPage {
        public function setOnloadHandler( $js ) { $this->mOnloadHandler = $js; }
        public function getOnloadHandler() { return $this->mOnloadHandler; }
        public function disable() { $this->mDoNothing = true; }
+       public function isDisabled() { return $this->mDoNothing; }
 
        public function setArticleRelated( $v ) {
                $this->mIsArticleRelated = $v;
@@ -416,7 +465,7 @@ class OutputPage {
                                        if ( array_key_exists( $category, $categories ) )
                                                continue;
                                $text = $wgContLang->convertHtml( $title->getText() );
-                               $this->mCategoryLinks[$type][] = $sk->makeLinkObj( $title, $text );
+                               $this->mCategoryLinks[$type][] = $sk->link( $title, $text );
                        }
                }
        }
@@ -475,8 +524,8 @@ class OutputPage {
         * @param bool   $linestart
         */
        public function addWikiText( $text, $linestart = true ) {
-               global $wgTitle;
-               $this->addWikiTextTitle($text, $wgTitle, $linestart);
+               $title = $this->getTitle(); // Work arround E_STRICT
+               $this->addWikiTextTitle( $text, $title, $linestart );
        }
 
        public function addWikiTextWithTitle($text, &$title, $linestart = true) {
@@ -512,7 +561,7 @@ class OutputPage {
         * @param ParserOutput object &$parserOutput
         */
        public function addParserOutputNoText( &$parserOutput ) {
-               global $wgTitle, $wgExemptFromUserRobotsControl, $wgContentNamespaces;
+               global $wgExemptFromUserRobotsControl, $wgContentNamespaces;
 
                $this->mLanguageLinks += $parserOutput->getLanguageLinks();
                $this->addCategoryLinks( $parserOutput->getCategories() );
@@ -524,7 +573,7 @@ class OutputPage {
                } else {
                        $bannedNamespaces = $wgExemptFromUserRobotsControl;
                }
-               if( !in_array( $wgTitle->getNamespace(), $bannedNamespaces ) ) {
+               if( !in_array( $this->getTitle()->getNamespace(), $bannedNamespaces ) ) {
                        # FIXME (bug 14900): This overrides $wgArticleRobotPolicies, and it
                        # shouldn't
                        $this->setIndexPolicy( $parserOutput->getIndexPolicy() );
@@ -584,7 +633,7 @@ class OutputPage {
         * @deprecated Use Article::outputWikitext
         */
        public function addPrimaryWikiText( $text, $article, $cache = true ) {
-               global $wgParser, $wgUser;
+               global $wgParser;
 
                wfDeprecated( __METHOD__ );
 
@@ -595,7 +644,7 @@ class OutputPage {
                $popts->setTidy(false);
                if ( $cache && $article && $parserOutput->getCacheTime() != -1 ) {
                        $parserCache = ParserCache::singleton();
-                       $parserCache->save( $parserOutput, $article, $wgUser );
+                       $parserCache->save( $parserOutput, $article, $popts);
                }
 
                $this->addParserOutput( $parserOutput );
@@ -605,17 +654,16 @@ class OutputPage {
         * @deprecated use addWikiTextTidy()
         */
        public function addSecondaryWikiText( $text, $linestart = true ) {
-               global $wgTitle;
                wfDeprecated( __METHOD__ );
-               $this->addWikiTextTitleTidy($text, $wgTitle, $linestart);
+               $this->addWikiTextTitleTidy($text, $this->getTitle(), $linestart);
        }
 
        /**
         * Add wikitext with tidy enabled
         */
        public function addWikiTextTidy(  $text, $linestart = true ) {
-               global $wgTitle;
-               $this->addWikiTextTitleTidy($text, $wgTitle, $linestart);
+               $title = $this->getTitle();
+               $this->addWikiTextTitleTidy($text, $title, $linestart);
        }
 
 
@@ -639,13 +687,13 @@ class OutputPage {
         * @param bool   $interface ??
         */
        public function parse( $text, $linestart = true, $interface = false ) {
-               global $wgParser, $wgTitle;
-               if( is_null( $wgTitle ) ) {
-                       throw new MWException( 'Empty $wgTitle in ' . __METHOD__ );
+               global $wgParser;
+               if( is_null( $this->getTitle() ) ) {
+                       throw new MWException( 'Empty $mTitle in ' . __METHOD__ );
                }
                $popts = $this->parserOptions();
                if ( $interface) { $popts->setInterfaceMessage(true); }
-               $parserOutput = $wgParser->parse( $text, $wgTitle, $popts,
+               $parserOutput = $wgParser->parse( $text, $this->getTitle(), $popts,
                        $linestart, true, $this->mRevisionId );
                if ( $interface) { $popts->setInterfaceMessage(false); }
                return $parserOutput->getText();
@@ -666,13 +714,16 @@ class OutputPage {
        /**
         * @param Article $article
         * @param User    $user
+        * 
+        * @deprecated
         *
         * @return bool True if successful, else false.
         */
-       public function tryParserCache( &$article, $user ) {
-               $parserCache = ParserCache::singleton();
-               $parserOutput = $parserCache->get( $article, $user );
-               if ( $parserOutput !== false ) {
+       public function tryParserCache( &$article ) {
+               wfDeprecated( __METHOD__ );
+               $parserOutput = ParserCache::singleton()->get( $article, $article->getParserOptions() );
+               
+               if ($parserOutput !== false) {
                        $this->addParserOutput( $parserOutput );
                        return true;
                } else {
@@ -823,7 +874,7 @@ class OutputPage {
                global $wgContLanguageCode, $wgDebugRedirects, $wgMimeType;
                global $wgJsMimeType, $wgUseAjax, $wgAjaxWatch;
                global $wgEnableMWSuggest, $wgUniversalEditButton;
-               global $wgArticle, $wgTitle;
+               global $wgArticle;
 
                if( $this->mDoNothing ){
                        return;
@@ -931,20 +982,20 @@ class OutputPage {
                }
 
                if( $wgUniversalEditButton ) {
-                       if( isset( $wgArticle ) && isset( $wgTitle ) && $wgTitle->quickUserCan( 'edit' )
-                               && ( $wgTitle->exists() || $wgTitle->quickUserCan( 'create' ) ) ) {
+                       if( isset( $wgArticle ) && $this->getTitle() && $this->getTitle()->quickUserCan( 'edit' )
+                               && ( $this->getTitle()->exists() || $this->getTitle()->quickUserCan( 'create' ) ) ) {
                                // Original UniversalEditButton
                                $this->addLink( array(
                                        'rel' => 'alternate',
                                        'type' => 'application/x-wiki',
                                        'title' => wfMsg( 'edit' ),
-                                       'href' => $wgTitle->getFullURL( 'action=edit' )
+                                       'href' => $this->getTitle()->getLocalURL( 'action=edit' )
                                ) );
                                // Alternate edit link
                                $this->addLink( array(
                                        'rel' => 'edit',
                                        'title' => wfMsg( 'edit' ),
-                                       'href' => $wgTitle->getFullURL( 'action=edit' )
+                                       'href' => $this->getTitle()->getLocalURL( 'action=edit' )
                                ) );
                        }
                }
@@ -973,8 +1024,9 @@ class OutputPage {
        }
 
        /**
-        * @todo document
-        * @param string $ins
+        * Actually output something with print(). Performs an iconv to the
+        * output encoding, if needed.
+        * @param string $ins The string to output
         */
        public function out( $ins ) {
                global $wgInputEncoding, $wgOutputEncoding, $wgContLang;
@@ -992,7 +1044,7 @@ class OutputPage {
         */
        public static function setEncodings() {
                global $wgInputEncoding, $wgOutputEncoding;
-               global $wgUser, $wgContLang;
+               global $wgContLang;
 
                $wgInputEncoding = strtolower( $wgInputEncoding );
 
@@ -1021,7 +1073,7 @@ class OutputPage {
         * @return nothing
         */
        function blockedPage( $return = true ) {
-               global $wgUser, $wgContLang, $wgTitle, $wgLang;
+               global $wgUser, $wgContLang, $wgLang;
 
                $this->setPageTitle( wfMsg( 'blockedtitle' ) );
                $this->setRobotPolicy( 'noindex,nofollow' );
@@ -1071,7 +1123,7 @@ class OutputPage {
 
                # Don't auto-return to special pages
                if( $return ) {
-                       $return = $wgTitle->getNamespace() > -1 ? $wgTitle : NULL;
+                       $return = $this->getTitle()->getNamespace() > -1 ? $this->getTitle() : null;
                        $this->returnToMain( null, $return );
                }
        }
@@ -1084,9 +1136,8 @@ class OutputPage {
         * @param array $params Message parameters
         */
        public function showErrorPage( $title, $msg, $params = array() ) {
-               global $wgTitle;
-               if ( isset($wgTitle) ) {
-                       $this->mDebugtext .= 'Original title: ' . $wgTitle->getPrefixedText() . "\n";
+               if ( $this->getTitle() ) {
+                       $this->mDebugtext .= 'Original title: ' . $this->getTitle()->getPrefixedText() . "\n";
                }
                $this->setPageTitle( wfMsg( $title ) );
                $this->setHTMLTitle( wfMsg( 'errorpagetitle' ) );
@@ -1110,10 +1161,8 @@ class OutputPage {
         */
        public function showPermissionsErrorPage( $errors, $action = null )
        {
-               global $wgTitle;
-
                $this->mDebugtext .= 'Original title: ' .
-               $wgTitle->getPrefixedText() . "\n";
+               $this->getTitle()->getPrefixedText() . "\n";
                $this->setPageTitle( wfMsg( 'permissionserrors' ) );
                $this->setHTMLTitle( wfMsg( 'permissionserrors' ) );
                $this->setRobotPolicy( 'noindex,nofollow' );
@@ -1153,7 +1202,7 @@ class OutputPage {
         * @param string $permission key required
         */
        public function permissionRequired( $permission ) {
-               global $wgUser;
+               global $wgLang;
 
                $this->setPageTitle( wfMsg( 'badaccess' ) );
                $this->setHTMLTitle( wfMsg( 'errorpagetitle' ) );
@@ -1165,7 +1214,7 @@ class OutputPage {
                        User::getGroupsWithPermission( $permission ) );
                if( $groups ) {
                        $this->addWikiMsg( 'badaccess-groups',
-                               implode( ', ', $groups ),
+                               $wgLang->commaList( $groups ),
                                count( $groups) );
                } else {
                        $this->addWikiMsg( 'badaccess-group0' );
@@ -1193,7 +1242,7 @@ class OutputPage {
         * Produce the stock "please login to use the wiki" page
         */
        public function loginToUse() {
-               global $wgUser, $wgTitle, $wgContLang;
+               global $wgUser, $wgContLang;
 
                if( $wgUser->isLoggedIn() ) {
                        $this->permissionRequired( 'read' );
@@ -1208,9 +1257,15 @@ class OutputPage {
                $this->setArticleFlag( false );
 
                $loginTitle = SpecialPage::getTitleFor( 'Userlogin' );
-               $loginLink = $skin->makeKnownLinkObj( $loginTitle, wfMsgHtml( 'loginreqlink' ), 'returnto=' . $wgTitle->getPrefixedUrl() );
+               $loginLink = $skin->link(
+                       $loginTitle,
+                       wfMsgHtml( 'loginreqlink' ),
+                       array(),
+                       array( 'returnto' => $this->getTitle()->getPrefixedText() ),
+                       array( 'known', 'noclasses' )
+               );
                $this->addHTML( wfMsgWikiHtml( 'loginreqpagetext', $loginLink ) );
-               $this->addHTML( "\n<!--" . $wgTitle->getPrefixedUrl() . "-->" );
+               $this->addHTML( "\n<!--" . $this->getTitle()->getPrefixedUrl() . "-->" );
 
                # Don't return to the main page if the user can't read it
                # otherwise we'll end up in a pointless loop
@@ -1233,7 +1288,7 @@ class OutputPage {
                        $text = wfMsgNoTrans( 'permissionserrorstext', count($errors)). "\n\n";
                } else {
                        global $wgLang;
-                       $action_desc = wfMsg( "action-$action" );
+                       $action_desc = wfMsgNoTrans( "action-$action" );
                        $text = wfMsgNoTrans( 'permissionserrorstext-withaction', count($errors), $action_desc ) . "\n\n";
                }
 
@@ -1248,7 +1303,7 @@ class OutputPage {
                        }
                        $text .= '</ul>';
                } else {
-                       $text .= '<div class="permissions-errors">' . call_user_func_array( 'wfMsgNoTrans', reset( $errors ) ) . '</div>';
+                       $text .= "<div class=\"permissions-errors\">\n" . call_user_func_array( 'wfMsgNoTrans', reset( $errors ) ) . "\n</div>";
                }
 
                return $text;
@@ -1274,7 +1329,7 @@ class OutputPage {
         * @param array  $reasons   List of reasons for this error, as returned by Title::getUserPermissionsErrors().
         */
        public function readOnlyPage( $source = null, $protected = false, $reasons = array(), $action = null ) {
-               global $wgUser, $wgTitle;
+               global $wgUser;
                $skin = $wgUser->getSkin();
 
                $this->setRobotPolicy( 'noindex,nofollow' );
@@ -1290,7 +1345,18 @@ class OutputPage {
                        // Permissions error
                        if( $source ) {
                                $this->setPageTitle( wfMsg( 'viewsource' ) );
-                               $this->setSubtitle( wfMsg( 'viewsourcefor', $skin->makeKnownLinkObj( $wgTitle ) ) );
+                               $this->setSubtitle(
+                                       wfMsg(
+                                               'viewsourcefor',
+                                               $skin->link(
+                                                       $this->getTitle(),
+                                                       null,
+                                                       array(),
+                                                       array(),
+                                                       array( 'known', 'noclasses' )
+                                               )
+                                       )
+                               );
                        } else {
                                $this->setPageTitle( wfMsg( 'badaccess' ) );
                        }
@@ -1317,7 +1383,7 @@ class OutputPage {
 
                        // Show templates used by this article
                        $skin = $wgUser->getSkin();
-                       $article = new Article( $wgTitle );
+                       $article = new Article( $this->getTitle() );
                        $this->addHTML( "<div class='templatesUsed'>
 {$skin->formatTemplates( $article->getUsedTemplates() )}
 </div>
@@ -1327,8 +1393,8 @@ class OutputPage {
                # If the title doesn't exist, it's fairly pointless to print a return
                # link to it.  After all, you just tried editing it and couldn't, so
                # what's there to do there?
-               if( $wgTitle->exists() ) {
-                       $this->returnToMain( null, $wgTitle );
+               if( $this->getTitle()->exists() ) {
+                       $this->returnToMain( null, $this->getTitle() );
                }
        }
 
@@ -1405,8 +1471,8 @@ class OutputPage {
        public function addReturnTo( $title ) {
                global $wgUser;
                $this->addLink( array( 'rel' => 'next', 'href' => $title->getFullUrl() ) );
-               $link = wfMsg( 'returnto', $wgUser->getSkin()->makeLinkObj( $title ) );
-               $this->addHTML( "<p>{$link}</p>\n" );
+               $link = wfMsgHtml( 'returnto', $wgUser->getSkin()->link( $title ) );
+               $this->addHTML( "<p id=\"mw-returnto\">{$link}</p>\n" );
        }
 
        /**
@@ -1440,14 +1506,23 @@ class OutputPage {
        }
 
        /**
-        * This function takes the title (first item of mGoodLinks), categories, existing and broken links for the page
+        * This function takes the title (first item of mGoodLinks), categories,
+        * existing and broken links for the page
         * and uses the first 10 of them for META keywords
         *
         * @param ParserOutput &$parserOutput
         */
        private function addKeywords( &$parserOutput ) {
-               global $wgTitle;
-               $this->addKeyword( $wgTitle->getPrefixedText() );
+               global $wgContLang;
+               // Get an array of keywords if there are more than one
+               // variant of the site language
+               $text = $wgContLang->autoConvertToAllVariants( $this->getTitle()->getPrefixedText());
+               // array_values: We needn't to merge variant's code name
+               // into $this->mKeywords;
+               // array_unique: We should insert a keyword just for once
+               if( is_array( $text ))
+                       $text = array_unique( array_values( $text ));
+               $this->addKeyword( $text );
                $count = 1;
                $links2d =& $parserOutput->getLinks();
                if ( !is_array( $links2d ) ) {
@@ -1455,6 +1530,9 @@ class OutputPage {
                }
                foreach ( $links2d as $dbkeys ) {
                        foreach( $dbkeys as $dbkey => $unused ) {
+                               $dbkey = $wgContLang->autoConvertToAllVariants( $dbkey );
+                               if( is_array( $dbkey ))
+                                       $dbkey = array_unique( array_values( $dbkey ));
                                $this->addKeyword( $dbkey );
                                if ( ++$count > 10 ) {
                                        break 2;
@@ -1469,36 +1547,37 @@ class OutputPage {
        public function headElement( Skin $sk ) {
                global $wgDocType, $wgDTD, $wgContLanguageCode, $wgOutputEncoding, $wgMimeType;
                global $wgXhtmlDefaultNamespace, $wgXhtmlNamespaces;
-               global $wgUser, $wgContLang, $wgUseTrackbacks, $wgTitle, $wgStyleVersion;
+               global $wgContLang, $wgUseTrackbacks, $wgStyleVersion;
 
-               $this->addMeta( "http:Content-type", "$wgMimeType; charset={$wgOutputEncoding}" );
-               $this->addStyle( 'common/wikiprintable.css', 'print' );
+               $this->addMeta( "http:Content-Type", "$wgMimeType; charset={$wgOutputEncoding}" );
+               if ( $sk->commonPrintStylesheet() ) {
+                       $this->addStyle( 'common/wikiprintable.css', 'print' );
+               }
                $sk->setupUserCss( $this );
 
                $ret = '';
 
                if( $wgMimeType == 'text/xml' || $wgMimeType == 'application/xhtml+xml' || $wgMimeType == 'application/xml' ) {
-                       $ret .= "<?xml version=\"1.0\" encoding=\"$wgOutputEncoding\" ?>\n";
+                       $ret .= "<?xml version=\"1.0\" encoding=\"$wgOutputEncoding\" ?" . ">\n";
                }
 
-               $ret .= "<!DOCTYPE html PUBLIC \"$wgDocType\"\n        \"$wgDTD\">\n";
+               $ret .= "<!DOCTYPE html PUBLIC \"$wgDocType\" \"$wgDTD\">\n";
 
                if ( '' == $this->getHTMLTitle() ) {
                        $this->setHTMLTitle(  wfMsg( 'pagetitle', $this->getPageTitle() ));
                }
 
-               $rtl = $wgContLang->isRTL() ? " dir='RTL'" : '';
+               $dir = $wgContLang->isRTL() ? 'rtl' : 'ltr';
                $ret .= "<html xmlns=\"{$wgXhtmlDefaultNamespace}\" ";
                foreach($wgXhtmlNamespaces as $tag => $ns) {
                        $ret .= "xmlns:{$tag}=\"{$ns}\" ";
                }
-               $ret .= "xml:lang=\"$wgContLanguageCode\" lang=\"$wgContLanguageCode\" $rtl>\n";
-               $ret .= "<head>\n<title>" . htmlspecialchars( $this->getHTMLTitle() ) . "</title>\n\t\t";
-               $ret .= implode( "\t\t", array(
+               $ret .= "xml:lang=\"$wgContLanguageCode\" lang=\"$wgContLanguageCode\" dir=\"$dir\">\n";
+               $ret .= "<head>\n\t<title>" . htmlspecialchars( $this->getHTMLTitle() ) . "</title>\n\t";
+               $ret .= implode( "\n", array(
                        $this->getHeadLinks(),
                        $this->buildCssLinks(),
-                       $sk->getHeadScripts( $this->mAllowUserJs ),
-                       $this->mScripts,
+                       $sk->getHeadScripts( $this->mAllowUserJs, $this->mScripts ),
                        $this->getHeadItems(),
                ));
                if( $sk->usercss ){
@@ -1506,7 +1585,7 @@ class OutputPage {
                }
 
                if ($wgUseTrackbacks && $this->isArticleRelated())
-                       $ret .= $wgTitle->trackbackRDF();
+                       $ret .= $this->getTitle()->trackbackRDF();
 
                $ret .= "</head>\n";
                return $ret;
@@ -1514,6 +1593,14 @@ class OutputPage {
        
        protected function addDefaultMeta() {
                global $wgVersion;
+
+               static $called = false;
+               if ( $called ) {
+                       # Don't run this twice
+                       return;
+               }
+               $called = true;
+
                $this->addMeta( 'http:Content-Style-Type', 'text/css' ); //bug 15835
                $this->addMeta( 'generator', "MediaWiki $wgVersion" );
                
@@ -1526,7 +1613,7 @@ class OutputPage {
 
                if ( count( $this->mKeywords ) > 0 ) {
                        $strip = array(
-                               "/<.*?>/" => '',
+                               "/<.*?" . ">/" => '',
                                "/_/" => ' '
                        );
                        $this->addMeta( 'keywords', preg_replace(array_keys($strip), array_values($strip),implode( ",", $this->mKeywords ) ) );
@@ -1561,7 +1648,6 @@ class OutputPage {
                }
 
                if( $wgFeed ) {
-                       global $wgTitle;
                        foreach( $this->getSyndicationLinks() as $format => $link ) {
                                # Use the page name for the title (accessed through $wgTitle since
                                # there's no other way).  In principle, this could lead to issues
@@ -1571,7 +1657,7 @@ class OutputPage {
                                $tags[] = $this->feedLink(
                                        $format,
                                        $link,
-                                       wfMsg( "page-{$format}-feed", $wgTitle->getPrefixedText() ) ); # Used messages: 'page-rss-feed' and 'page-atom-feed' (for an easier grep)
+                                       wfMsg( "page-{$format}-feed", $this->getTitle()->getPrefixedText() ) ); # Used messages: 'page-rss-feed' and 'page-atom-feed' (for an easier grep)
                        }
 
                        # Recent changes feed should appear on every page (except recentchanges, 
@@ -1593,17 +1679,17 @@ class OutputPage {
                                                wfMsg( "site-{$type}-feed", $wgSitename ) );
                                }
                        }
-                       else if ( $wgTitle->getPrefixedText() != $rctitle->getPrefixedText() ) {
+                       else if ( $this->getTitle()->getPrefixedText() != $rctitle->getPrefixedText() ) {
                                foreach( $wgFeedClasses as $format => $class ) {
                                        $tags[] = $this->feedLink(
                                                $format,
-                                               $rctitle->getFullURL( "feed={$format}" ),
+                                               $rctitle->getLocalURL( "feed={$format}" ),
                                                wfMsg( "site-{$format}-feed", $wgSitename ) ); # For grep: 'site-rss-feed', 'site-atom-feed'.
                                }
                        }
                }
 
-               return implode( "\n\t\t", $tags ) . "\n";
+               return implode( "\n\t", $tags ) . "\n";
        }
 
        /**
@@ -1611,7 +1697,7 @@ class OutputPage {
         * @return array associating format keys with URLs
         */
        public function getSyndicationLinks() {
-               global $wgTitle, $wgFeedClasses;
+               global $wgFeedClasses;
                $links = array();
 
                if( $this->isSyndicated() ) {
@@ -1622,7 +1708,7 @@ class OutputPage {
                        }
 
                        foreach( $wgFeedClasses as $format => $class ) {
-                               $links[$format] = $wgTitle->getLocalUrl( "feed=$format{$appendQuery}" );
+                               $links[$format] = $this->getTitle()->getLocalUrl( "feed=$format{$appendQuery}" );
                        }
                }
                return $links;
@@ -1670,7 +1756,7 @@ class OutputPage {
                                $links[] = $link;
                }
 
-               return implode( "\n\t\t", $links );
+               return "\t" . implode( "\n\t", $links );
        }
 
        protected function styleLink( $style, $options ) {
@@ -1756,7 +1842,6 @@ class OutputPage {
         * for when rate limiting has triggered.
         */
        public function rateLimited() {
-               global $wgTitle;
 
                $this->setPageTitle(wfMsg('actionthrottled'));
                $this->setRobotPolicy( 'noindex,follow' );
@@ -1767,7 +1852,7 @@ class OutputPage {
                $this->setStatusCode(503);
                $this->addWikiMsg( 'actionthrottledtext' );
 
-               $this->returnToMain( null, $wgTitle );
+               $this->returnToMain( null, $this->getTitle() );
        }
 
        /**
@@ -1839,7 +1924,7 @@ class OutputPage {
         *
         * In the $wrap, $1 is replaced with the first message, $2 with the second, and so
         * on. The subsequent arguments may either be strings, in which case they are the
-        * message names, or an arrays, in which case the first element is the message name,
+        * message names, or arrays, in which case the first element is the message name,
         * and subsequent elements are the parameters to that message.
         *
         * The special named parameter 'options' in a message specification array is passed