Fix retarded mistake in 57997, move break to within the if block or it defeats the...
[lhc/web/wiklou.git] / includes / OutputPage.php
index 93318e6..7879cbb 100644 (file)
@@ -15,10 +15,10 @@ class OutputPage {
        var $mCategoryLinks = array(), $mLanguageLinks = array();
 
        var $mScriptLoaderClassList = array();
-       // the most recent id of any script that is grouped in the script request
-       var $mLatestScriptRevID = 0; 
 
        var $mScripts = '', $mLinkColours, $mPageLinkTitle = '', $mHeadItems = array();
+       var $mInlineMsg = array();
+
        var $mTemplateIds = array();
 
        var $mAllowUserJs;
@@ -28,8 +28,9 @@ class OutputPage {
        var $mContainsOldMagic = 0, $mContainsNewMagic = 0;
        var $mIsArticleRelated = true;
        protected $mParserOptions = null; // lazy initialised, use parserOptions()
-       var $mShowFeedLinks = false;
-       var $mFeedLinksAppendQuery = false;
+       
+       var $mFeedLinks = array();
+       
        var $mEnableClientCache = true;
        var $mArticleBodyOnly = false;
 
@@ -97,11 +98,19 @@ class OutputPage {
                        array_push( $this->mKeywords, $text );
                }
        }
-       function addScript( $script ) { $this->mScripts .= "\t\t" . $script . "\n"; }
+       function addScript( $script ) {
+               $this->mScripts .= $script . "\n";
+       }
 
-       function addExtensionStyle( $url ) {
-               $linkarr = array( 'rel' => 'stylesheet', 'href' => $url, 'type' => 'text/css' );
-               array_push( $this->mExtStyles, $linkarr );
+       /**
+        * Register and add a stylesheet from an extension directory.
+        * @param $url String path to sheet.  Provide either a full url (beginning
+        *             with 'http', etc) or a relative path from the document root
+        *             (beginning with '/').  Otherwise it behaves identically to
+        *             addStyle() and draws from the /skins folder.
+        */
+       public function addExtensionStyle( $url ) {
+               array_push( $this->mExtStyles, $url );
        }
 
        /**
@@ -109,8 +118,8 @@ class OutputPage {
         * @param string $file filename in skins/common or complete on-server path (/foo/bar.js)
         */
        function addScriptFile( $file ) {
-               global $wgStylePath, $wgStyleVersion, $wgJsMimeType, $wgScript, $wgUser;
-               global $wgJSAutoloadClasses, $wgJSAutoloadLocalClasses, $wgEnableScriptLoader, $wgScriptPath;
+               global $wgStylePath, $wgScript, $wgUser;
+               global $wgEnableScriptLoader, $wgScriptPath;
 
                if( substr( $file, 0, 1 ) == '/' ) {
                        $path = $file;
@@ -118,61 +127,54 @@ class OutputPage {
                        $path = "{$wgStylePath}/common/{$file}";
                }
 
-               if( $wgEnableScriptLoader ){
-                       if( strpos( $path, $wgScript ) !== false ){
-                               $reqPath = str_replace( $wgScript . '?', '', $path );
-                               $reqArgs = explode( '&', $reqPath );
-                               $reqSet = array();
-
-                               foreach( $reqArgs as $arg ){
-                                       list( $key, $var ) = explode( '=', $arg );
-                                       $reqSet[$key] = $var;
-                               }
+               // If the class can be determined, use the addScriptClass method
+               $js_class = $this->getJsClassFromPath( $path );
+               if( $js_class ) {
+                       $this->addScriptClass( $js_class );
+                       return true;
+               }
 
-                               if( isset( $reqSet['title'] ) && $reqSet != '' ) {
-                                       // extract any extra param (for now just skin)
-                                       $ext_param = ( isset( $reqSet['useskin'] ) && $reqSet['useskin'] != '' ) ? '|useskin=' . ucfirst( $reqSet['useskin'] ) : '';
-                                       $this->mScriptLoaderClassList[] = 'WT:' . $reqSet['title'] . $ext_param ;
-                                       // add the title revision to the key
-                                       $t = Title::newFromText( $reqSet['title'] );
-                                       // if there is no title (don't worry we just use the $wgStyleVersion var (which should be updated on relevant commits)
-                                       if( $t->exists() ){
-                                               if( $t->getLatestRevID() > $this->mLatestScriptRevID  )
-                                                       $this->mLatestScriptRevID = $t->getLatestRevID();
-                                       }
-                                       return true;
-                               }
+               //do checks for wiki-titles
+               if( strpos( $path, $wgScript ) !== false ) {
+                       $reqPath = str_replace( $wgScript . '?', '', $path );
+                       $reqArgs = explode( '&', $reqPath );
+                       $reqSet = array();
+
+                       foreach( $reqArgs as $arg ) {
+                               list( $key, $var ) = explode( '=', $arg );
+                               $reqSet[$key] = $var;
                        }
 
-                       // check for class from path:
-                       $js_class = $this->getJsClassFromPath( $path );
-                       if( $js_class ){
-                               // add to the class list:
-                               $this->mScriptLoaderClassList[] = $js_class;
-                               return true;
+                       if( isset( $reqSet['title'] ) && $reqSet != '' ) {
+                               $jsTitleClass = 'WT:' . $reqSet['title'];
+                               if( $wgEnableScriptLoader ) {
+                                       // Extract any extra parameters (for now just skin)
+                                       $ext_param = ( isset( $reqSet['useskin'] ) && $reqSet['useskin'] != '' )
+                                               ? '|useskin=' . ucfirst( $reqSet['useskin'] ) : '';
+                                       $this->mScriptLoaderClassList[] = $jsTitleClass . $ext_param ;
+                                       return true;
+                               }else{
+                                       $this->addScript( Html::linkedScript(
+                                                               wfAppendQuery( $path, $this->getURIDparam( $jsTitleClass ) )
+                                                       )
+                                               );
+                                       return true;
+                               }
                        }
                }
-
-               // if the script loader did not find a way to add the script than add using addScript
-               $this->addScript(
-                       Xml::element( 'script',
-                               array(
-                                       'type' => $wgJsMimeType,
-                                       'src' => wfAppendQuery( $path, $this->getURIDparam() ),
-                               ),
-                               '', false
-                       )
-               );
+               // If the script loader could not be used, just add the script to the header
+               $this->addScript( Html::linkedScript( wfAppendQuery( $path, $this->getURIDparam() ) ) );
        }
 
        /**
-        * This is the core script that is included on every page
-        * (they are requested separately to improve caching across
-        *  different page load types (edit, upload, view, etc)
+        * Add the core scripts that are included on every page, for later output into the header
+        *
+        * this includes the conditional sitejs
         */
        function addCoreScripts2Top(){
-               global $wgEnableScriptLoader, $wgStyleVersion, $wgJSAutoloadLocalClasses, $wgJsMimeType, $wgScriptPath, $wgEnableJS2system;
-               //@@todo we should deprecate wikibits in favor of mv_embed and native jQuery functions
+               global $wgEnableScriptLoader, $wgJSAutoloadLocalClasses, $wgScriptPath, $wgEnableJS2system;
+               global $wgUser, $wgJsMimeType;
+               // @todo We should deprecate wikibits in favor of some mv_embed pieces and jQuery
 
                if( $wgEnableJS2system ){
                        $core_classes = array( 'window.jQuery', 'mv_embed', 'wikibits' );
@@ -180,105 +182,144 @@ class OutputPage {
                        $core_classes = array( 'wikibits' );
                }
 
+               //make sure scripts are on top:
+               $postScripts = $this->mScripts;
+               $this->mScripts = '';
+
                if( $wgEnableScriptLoader ){
-                       $this->mScripts = $this->getScriptLoaderJs( $core_classes ) . $this->mScripts;
+                       //directly add script_loader call
+                       //(separate from other scriptloader calls that may include extensions with conditional js)
+                       $this->mScripts = $this->getScriptLoaderJs( $core_classes );
                } else {
                        $so = '';
-                       foreach( $core_classes as $s ){
-                               if( isset( $wgJSAutoloadLocalClasses[$s] ) ){
-                                       $so.= Xml::element( 'script', array(
-                                                       'type' => $wgJsMimeType,
-                                                       'src' => "{$wgScriptPath}/{$wgJSAutoloadLocalClasses[$s]}?" . $this->getURIDparam()
-                                               ),
-                                               '', false
-                                       );
-                               }
+                       foreach( $core_classes as $js_class ){
+                               $this->addScriptClass( $js_class );
                        }
-                       $this->mScripts =  $so . $this->mScripts;
                }
+               //now re-append any scripts that got added prior to the addCoreScripts2Top call
+               $this->mScripts = $this->mScripts . $postScripts;
        }
 
        /**
-        * @param $js_class String: name of JavaScript class
-        * @return Boolean: false if class wasn't found, true on success
+        * @param string $js_class Name of the JavaScript class
+        * @return boolean False if the class wasn't found, true on success
         */
        function addScriptClass( $js_class ){
-               global $wgJSAutoloadClasses, $wgJSAutoloadLocalClasses, $wgJsMimeType,
-                               $wgEnableScriptLoader, $wgStyleVersion, $wgScriptPath;
-
-               if( isset( $wgJSAutoloadClasses[$js_class] ) || isset( $wgJSAutoloadLocalClasses[$js_class] ) ){
-                       if( $wgEnableScriptLoader ){
-                               if( !in_array( $js_class, $this->mScriptLoaderClassList ) ){
+               global $wgDebugJavaScript, $wgJSAutoloadLocalClasses, $wgJSAutoloadClasses,
+                               $wgEnableScriptLoader, $wgStyleVersion, $wgScriptPath, $wgStylePath, $wgEnableJS2system;
+
+               $path = jsScriptLoader::getJsPathFromClass( $js_class );
+               if( $path !== false ){
+                       if( $wgEnableScriptLoader ) {
+                               // Register it with the script loader
+                               if( !in_array( $js_class, $this->mScriptLoaderClassList ) ) {
                                        $this->mScriptLoaderClassList[] = $js_class;
                                }
                        } else {
-                               // do a normal load of without the script-loader:
-                               $path = $wgScriptPath . '/';
-                               $path.= isset( $wgJSAutoloadClasses[$js_class] ) ? $wgJSAutoloadClasses[$js_class]:
-                                                       $wgJSAutoloadLocalClasses[$js_class];
-                               $this->addScript(
-                                       Xml::element( 'script',
-                                               array(
-                                                       'type' => $wgJsMimeType,
-                                                       'src' => "$path?$wgStyleVersion",
-                                               ),
-                                               '', false
-                                       )
-                               );
+                               // Source the script directly
+                               $prefix = "skins/common/";
+                               if( substr( $path, 0, 1 ) == '/' ) {
+                                       // straight path
+                               } elseif( substr( $path, 0, strlen( $prefix ) ) == $prefix ) {
+                                       // Respect $wgStypePath
+                                       $path = "{$wgStylePath}/common/" . substr( $path, strlen( $prefix ) );
+                               } else {
+                                       $path = $wgScriptPath . '/' . $path;
+                               }
+                               $urlAppend = ( $wgDebugJavaScript ) ? time() : $this->getURIDparam( $js_class );
+                               $this->addScript( Html::linkedScript( "$path?$urlAppend" ) );
+
+                               //merge in language text (if js2 is on and we have loadGM function)
+                               if( $wgEnableJS2system ){
+                                       $inlineMsg = jsScriptLoader::getLocalizedMsgsFromClass( $js_class );
+                                       if( $inlineMsg != '' )
+                                               $this->addScript( Html::inlineScript( $inlineMsg ));
+                               }
                        }
                        return true;
                }
+               print "could not find: $js_class\n";
                wfDebug( __METHOD__ . ' could not find js_class: ' . $js_class );
                return false; // could not find the class
        }
 
        /**
-        * gets the scriptLoader javascript include
-        * @param $forcClassAry Boolean: false by default
+        * Get the <script> tag which will invoke the script loader
+        * @param $classAry A class array which, if given, overrides $this->mScriptLoaderClassList
         */
-       function getScriptLoaderJs( $forceClassAry = false ){
-               global $wgScriptPath, $wgJsMimeType, $wgStyleVersion, $wgRequest, $wgDebugJavaScript;
-
-               if( !$forceClassAry ){
-                       $class_list = implode( ',', $this->mScriptLoaderClassList );
-               } else {
-                       $class_list = implode( ',', $forceClassAry );
+       function getScriptLoaderJs( $classAry = array() ) {
+               global $wgRequest, $wgDebugJavaScript;
+               // If no class array was provided, use mScriptLoaderClassList
+               if( !count( $classAry ) ) {
+                       $classAry = $this->mScriptLoaderClassList;
                }
+               $class_list = implode( ',', $classAry );
 
                $debug_param = ( $wgDebugJavaScript ||
                                                 $wgRequest->getVal( 'debug' ) == 'true' ||
                                                 $wgRequest->getVal( 'debug' ) == '1' )
                                         ? '&debug=true' : '';
 
-               //@@todo intelligent unique id generation based on svn version of file (rather than just grabbing the $wgStyleVersion var)
-               //@@todo we should check the packaged message text in this javascript file for updates and update the $mScriptLoaderURID id (in getJsClassFromPath)
-
-               //generate the unique request param (combine with the most recent revision id of any wiki page with the $wgStyleVersion var)
-
-
-               return Xml::element( 'script',
-                               array(
-                                       'type' => $wgJsMimeType,
-                                       'src' => "$wgScriptPath/mwScriptLoader.php?class={$class_list}{$debug_param}&".$this->getURIDparam(),
-                               ),
-                               '', false
-               );
+               return Html::linkedScript( wfScript( 'mwScriptLoader' ) .
+                       "?class={$class_list}{$debug_param}&" . $this->getURIDparam( $classAry) ) . "\n";
        }
 
-       function getURIDparam(){
-               global $wgDebugJavaScript, $wgStyleVersion;
-               if( $wgDebugJavaScript ){
+       /**
+        * Get the unique request ID parameter for the script-loader request
+        */
+       function getURIDparam( $classAry = array() ) {
+               global $wgDebugJavaScript, $wgStyleVersion, $IP, $wgScriptModifiedCheck;
+               if( $wgDebugJavaScript ) {
                        return 'urid=' . time();
                } else {
-                       return "urid={$wgStyleVersion}_{$this->mLatestScriptRevID}";
+                       //support single class_name attr
+                       if( gettype( $classAry) == 'string'  ){
+                               $classAry = array( $classAry );
+                       }
+                       $ftime =  $frev = 0;
+                       foreach( $classAry as $class ) {
+                               if( $wgScriptModifiedCheck ) {
+                                       $js_path =  jsScriptLoader::getJsPathFromClass( $class );
+                                       if( $js_path ) {
+                                               $cur_ftime = filemtime ( $IP ."/". $js_path );
+                                               if( $cur_ftime > $ftime )
+                                                       $ftime = $cur_ftime;
+                                       }
+                               }
+                               // Add the latest revision ID if the class set includes a WT (wiki title)
+                               if( substr($class, 0, 3) == 'WT:'){
+                                       $title_str = substr($class, 3);
+                                       $t = Title::newFromText( $title_str );
+                                       if( $t && $t->exists() ) {
+                                               if( $t->getLatestRevID() > $frev  )
+                                                       $frev = $t->getLatestRevID();
+                                       }
+                               }
+                       }
+                       //build the actual unique request id:
+                       $urid = "urid={$wgStyleVersion}";
+
+                       // Add the file modification time if set
+                       if( $ftime != 0 )
+                               $urid .= "_" . $ftime;
+
+                       //add the wiki rev id if set
+                       if( $frev != 0 )
+                               $urid.= "_" . $frev;
+
+                       return $urid;
                }
        }
 
-       function getJsClassFromPath( $path ){
+       /**
+        * Given a script path, get the JS class name, or false if no such path is registered.
+        * @param $path string
+        */
+       function getJsClassFromPath( $path ) {
                global $wgJSAutoloadClasses, $wgJSAutoloadLocalClasses, $wgScriptPath;
 
                $scriptLoaderPaths = array_merge( $wgJSAutoloadClasses,  $wgJSAutoloadLocalClasses );
-               foreach( $scriptLoaderPaths as $js_class => $js_path ){
+               foreach( $scriptLoaderPaths as $js_class => $js_path ) {
                        $js_path = "{$wgScriptPath}/{$js_path}";
                        if( $path == $js_path )
                                return $js_class;
@@ -291,14 +332,15 @@ class OutputPage {
         * @param string $script JavaScript text, no <script> tags
         */
        function addInlineScript( $script ) {
-               global $wgJsMimeType;
-               $this->mScripts .= "\t\t<script type=\"$wgJsMimeType\">/*<![CDATA[*/\n\t\t$script\n\t\t/*]]>*/</script>\n";
+               $this->mScripts .= Html::inlineScript( "\n$script\n" ) . "\n";
        }
 
+       /**
+        * Get all registered JS and CSS tags for the header.
+        */
        function getScript() {
                global $wgEnableScriptLoader;
                if( $wgEnableScriptLoader ){
-                       //include $this->mScripts (for anything that we could not package into the scriptloader
                        return $this->mScripts . "\n" . $this->getScriptLoaderJs() . $this->getHeadItems();
                } else {
                        return $this->mScripts . $this->getHeadItems();
@@ -323,7 +365,7 @@ class OutputPage {
 
        function setETag($tag) { $this->mETag = $tag; }
        function setArticleBodyOnly($only) { $this->mArticleBodyOnly = $only; }
-       function getArticleBodyOnly($only) { return $this->mArticleBodyOnly; }
+       function getArticleBodyOnly() { return $this->mArticleBodyOnly; }
 
        function addLink( $linkarr ) {
                # $linkarr should be an associative array of attributes. We'll escape on output.
@@ -451,22 +493,14 @@ class OutputPage {
         * @return null
         */
        public function setRobotPolicy( $policy ) {
-               $policy = explode( ',', $policy );
-               $policy = array_map( 'trim', $policy );
+               $policy = Article::formatRobotPolicy( $policy );
 
-               # The default policy is follow, so if nothing is said explicitly, we
-               # do that.
-               if( in_array( 'nofollow', $policy ) ) {
-                       $this->mFollowPolicy = 'nofollow';
-               } else {
-                       $this->mFollowPolicy = 'follow';
-               }
-
-               if( in_array( 'noindex', $policy ) ) {
-                       $this->mIndexPolicy = 'noindex';
-               } else {
-                       $this->mIndexPolicy = 'index';
-               }
+               if( isset( $policy['index'] ) ){
+                       $this->setIndexPolicy( $policy['index'] );
+               }
+               if( isset( $policy['follow'] ) ){
+                       $this->setFollowPolicy( $policy['follow'] );
+               }
        }
 
        /**
@@ -550,14 +584,30 @@ class OutputPage {
        public function isArticle() { return $this->mIsarticle; }
        public function setPrintable() { $this->mPrintable = true; }
        public function isPrintable() { return $this->mPrintable; }
-       public function setSyndicated( $show = true ) { $this->mShowFeedLinks = $show; }
-       public function isSyndicated() { return $this->mShowFeedLinks; }
-       public function setFeedAppendQuery( $val ) { $this->mFeedLinksAppendQuery = $val; }
        public function getFeedAppendQuery() { return $this->mFeedLinksAppendQuery; }
        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 setSyndicated( $show = true ) { $this->mShowFeedLinks = $show; }
+       
+       public function setFeedAppendQuery( $val ) {
+               global $wgFeedClasses;
+               
+               $this->mFeedLinks = array();
+               
+               foreach( $wgFeedClasses as $type => $class ) {
+                       $query = "feed=$type&".$val;
+                       $this->mFeedLinks[$type] = $this->getTitle()->getLocalURL( $query );
+               }
+       }
+       
+       public function addFeedLink( $format, $href ) {
+               $this->mFeedLinks[$format] = $href;
+       }
+       
+       public function isSyndicated() { return count($this->mFeedLinks); }
 
        public function setArticleRelated( $v ) {
                $this->mIsArticleRelated = $v;
@@ -738,17 +788,6 @@ class OutputPage {
                $this->mNewSectionLink = $parserOutput->getNewSection();
                $this->mHideNewSectionLink = $parserOutput->getHideNewSection();
 
-               if( is_null( $wgExemptFromUserRobotsControl ) ) {
-                       $bannedNamespaces = $wgContentNamespaces;
-               } else {
-                       $bannedNamespaces = $wgExemptFromUserRobotsControl;
-               }
-               if( !in_array( $this->getTitle()->getNamespace(), $bannedNamespaces ) ) {
-                       # FIXME (bug 14900): This overrides $wgArticleRobotPolicies, and it
-                       # shouldn't
-                       $this->setIndexPolicy( $parserOutput->getIndexPolicy() );
-               }
-
                $this->mParseWarnings = $parserOutput->getWarnings();
                if ( $parserOutput->getCacheTime() == -1 ) {
                        $this->enableClientCache( false );
@@ -787,7 +826,7 @@ class OutputPage {
         */
        function addParserOutput( &$parserOutput ) {
                $this->addParserOutputNoText( $parserOutput );
-               $text = $parserOutput->getText();
+               $text = $parserOutput->getText();
                wfRunHooks( 'OutputPageBeforeHTML',array( &$this, &$text ) );
                $this->addHTML( $text );
        }
@@ -1043,7 +1082,7 @@ class OutputPage {
        public function output() {
                global $wgUser, $wgOutputEncoding, $wgRequest;
                global $wgContLanguageCode, $wgDebugRedirects, $wgMimeType;
-               global $wgJsMimeType, $wgUseAjax, $wgAjaxWatch;
+               global $wgUseAjax, $wgAjaxWatch;
                global $wgEnableMWSuggest, $wgUniversalEditButton;
                global $wgArticle;
 
@@ -1131,7 +1170,7 @@ class OutputPage {
 
                $sk = $wgUser->getSkin();
 
-               // add our core scripts to output
+               // Add our core scripts to output
                $this->addCoreScripts2Top();
 
                if ( $wgUseAjax ) {
@@ -1152,20 +1191,32 @@ class OutputPage {
                        $this->addScriptFile( 'rightclickedit.js' );
                }
 
+               global $wgUseAJAXCategories, $wgEnableJS2system;
+               if ($wgUseAJAXCategories && $wgEnableJS2system) {
+                       global $wgAJAXCategoriesNamespaces;
+
+                       $title = $this->getTitle();
+
+                       if( empty( $wgAJAXCategoriesNamespaces ) || in_array( $title->getNamespace(), $wgAJAXCategoriesNamespaces ) ) {
+                               $this->addScriptClass( 'ajaxCategories' );
+                       }
+               }
+
                if( $wgUniversalEditButton ) {
                        if( isset( $wgArticle ) && $this->getTitle() && $this->getTitle()->quickUserCan( 'edit' )
                                && ( $this->getTitle()->exists() || $this->getTitle()->quickUserCan( 'create' ) ) ) {
                                // Original UniversalEditButton
+                               $msg = wfMsg('edit');
                                $this->addLink( array(
                                        'rel' => 'alternate',
                                        'type' => 'application/x-wiki',
-                                       'title' => wfMsg( 'edit' ),
+                                       'title' => $msg,
                                        'href' => $this->getTitle()->getLocalURL( 'action=edit' )
                                ) );
                                // Alternate edit link
                                $this->addLink( array(
                                        'rel' => 'edit',
-                                       'title' => wfMsg( 'edit' ),
+                                       'title' => $msg,
                                        'href' => $this->getTitle()->getLocalURL( 'action=edit' )
                                ) );
                        }
@@ -1542,15 +1593,15 @@ class OutputPage {
                // Show source, if supplied
                if( is_string( $source ) ) {
                        $this->addWikiMsg( 'viewsourcetext' );
-                       $text = Xml::openElement( 'textarea',
-                                               array( 'id'   => 'wpTextbox1',
-                                                      'name' => 'wpTextbox1',
-                                                      'cols' => $wgUser->getOption( 'cols' ),
-                                                      'rows' => $wgUser->getOption( 'rows' ),
-                                                      'readonly' => 'readonly' ) );
-                       $text .= htmlspecialchars( $source );
-                       $text .= Xml::closeElement( 'textarea' );
-                       $this->addHTML( $text );
+
+                       $params = array(
+                               'id'   => 'wpTextbox1',
+                               'name' => 'wpTextbox1',
+                               'cols' => $wgUser->getOption( 'cols' ),
+                               'rows' => $wgUser->getOption( 'rows' ),
+                               'readonly' => 'readonly'
+                       );
+                       $this->addHTML( Html::element( 'textarea', $params, $source ) );
 
                        // Show templates used by this article
                        $skin = $wgUser->getSkin();
@@ -1661,7 +1712,7 @@ class OutputPage {
                if ( $returnto == null ) {
                        $returnto = $wgRequest->getText( 'returnto' );
                }
-               
+
                if ( $returntoquery == null ) {
                        $returntoquery = $wgRequest->getText( 'returntoquery' );
                }
@@ -1684,8 +1735,10 @@ class OutputPage {
 
        /**
         * @return string The doctype, opening <html>, and head element.
+        *
+        * @param $sk Skin The given Skin
         */
-       public function headElement( Skin $sk ) {
+       public function headElement( Skin $sk, $includeStyle = true ) {
                global $wgDocType, $wgDTD, $wgContLanguageCode, $wgOutputEncoding, $wgMimeType;
                global $wgXhtmlDefaultNamespace, $wgXhtmlNamespaces;
                global $wgContLang, $wgUseTrackbacks, $wgStyleVersion, $wgEnableScriptLoader, $wgHtml5;
@@ -1706,7 +1759,7 @@ class OutputPage {
                        $this->setHTMLTitle(  wfMsg( 'pagetitle', $this->getPageTitle() ));
                }
 
-               $dir = $wgContLang->isRTL() ? 'rtl' : 'ltr';
+               $dir = $wgContLang->getDir();
 
                if ( $wgHtml5 ) {
                        $ret .= "<!doctype html>\n";
@@ -1720,15 +1773,16 @@ class OutputPage {
                        $ret .= "xml:lang=\"$wgContLanguageCode\" lang=\"$wgContLanguageCode\" dir=\"$dir\">\n";
                }
 
-               $ret .= "<head>\n\t<title>" . htmlspecialchars( $this->getHTMLTitle() ) . "</title>\n\t";
+               $ret .= "<head>\n";
+               $ret .= "<title>" . htmlspecialchars( $this->getHTMLTitle() ) . "</title>\n";
                $ret .= implode( "\n", array(
                        $this->getHeadLinks(),
                        $this->buildCssLinks(),
-                       $sk->getHeadScripts( $this ),
+                       $this->getHeadScripts( $sk ),
                        $this->getHeadItems(),
                ));
                if( $sk->usercss ){
-                       $ret .= "<style type='text/css'>{$sk->usercss}</style>";
+                       $ret .= Html::inlineStyle( $sk->usercss );
                }
 
                if( $wgEnableScriptLoader )
@@ -1741,6 +1795,44 @@ class OutputPage {
                return $ret;
        }
 
+       /*
+        * gets the global variables and mScripts
+        *
+        * also adds userjs to the end if enabled:
+       */
+       function getHeadScripts( Skin $sk ) {
+               global $wgUser, $wgRequest, $wgJsMimeType, $wgUseSiteJs;
+
+               $vars = Skin::makeGlobalVariablesScript( $sk->getSkinName() );
+
+               //add site JS if enabled:
+               if( $wgUseSiteJs ) {
+                       $jsCache = $wgUser->isLoggedIn() ? '&smaxage=0' : '';
+                       $this->addScriptFile(  Skin::makeUrl( '-',
+                                       "action=raw$jsCache&gen=js&useskin=" .
+                                       urlencode( $sk->getSkinName() )
+                                       )
+                               );
+               }
+
+               //add user js if enabled:
+               if( $this->isUserJsAllowed() && $wgUser->isLoggedIn() ) {
+                       $action = $wgRequest->getVal( 'action', 'view' );
+                       if( $this->mTitle && $this->mTitle->isJsSubpage() and $sk->userCanPreview( $action ) ) {
+                               # XXX: additional security check/prompt?
+                               $this->addInlineScript( $wgRequest->getText( 'wpTextbox1' ) );
+                       } else {
+                               $userpage = $wgUser->getUserPage();
+                               $userjs = Skin::makeUrl(
+                                       $userpage->getPrefixedText() . '/' . $sk->getSkinName() . '.js',
+                                       'action=raw&ctype=' . $wgJsMimeType );
+                               $this->addScriptFile( $userjs );
+                       }
+               }
+
+               return $vars . "\n" . $this->mScripts;
+       }
+
        protected function addDefaultMeta() {
                global $wgVersion, $wgHtml5;
 
@@ -1790,13 +1882,13 @@ class OutputPage {
                        } else {
                                $a = 'name';
                        }
-                       $tags[] = Xml::element( 'meta',
+                       $tags[] = Html::element( 'meta',
                                array(
                                        $a => $tag[0],
                                        'content' => $tag[1] ) );
                }
                foreach ( $this->mLinktags as $tag ) {
-                       $tags[] = Xml::element( 'link', $tag );
+                       $tags[] = Html::element( 'link', $tag );
                }
 
                if( $wgFeed ) {
@@ -1841,36 +1933,22 @@ class OutputPage {
                        }
                }
 
-               return implode( "\n\t", $tags ) . "\n";
+               return implode( "\n", $tags );
        }
 
        /**
         * Return URLs for each supported syndication format for this page.
         * @return array associating format keys with URLs
         */
-       public function getSyndicationLinks() {
-               global $wgFeedClasses;
-               $links = array();
-
-               if( $this->isSyndicated() ) {
-                       if( is_string( $this->getFeedAppendQuery() ) ) {
-                               $appendQuery = "&" . $this->getFeedAppendQuery();
-                       } else {
-                               $appendQuery = "";
-                       }
-
-                       foreach( $wgFeedClasses as $format => $class ) {
-                               $links[$format] = $this->getTitle()->getLocalUrl( "feed=$format{$appendQuery}" );
-                       }
-               }
-               return $links;
+       public function getSyndicationLinks() {         
+               return $this->mFeedLinks;
        }
 
        /**
         * Generate a <link rel/> for an RSS feed.
         */
        private function feedLink( $type, $url, $text ) {
-               return Xml::element( 'link', array(
+               return Html::element( 'link', array(
                        'rel' => 'alternate',
                        'type' => "application/$type+xml",
                        'title' => $text,
@@ -1887,6 +1965,8 @@ class OutputPage {
         */
        public function addStyle( $style, $media='', $condition='', $dir='' ) {
                $options = array();
+               // Even though we expect the media type to be lowercase, but here we
+               // force it to lowercase to be safe.
                if( $media )
                        $options['media'] = $media;
                if( $condition )
@@ -1901,7 +1981,7 @@ class OutputPage {
         * @param $style_css Mixed: inline CSS
         */
        public function addInlineStyle( $style_css ){
-               $this->mScripts .= "<style type=\"text/css\">$style_css</style>";
+               $this->mScripts .= Html::inlineStyle( $style_css );
        }
 
        /**
@@ -1916,7 +1996,7 @@ class OutputPage {
                                $links[] = $link;
                }
 
-               return "\t" . implode( "\n\t", $links );
+               return implode( "\n", $links );
        }
 
        protected function styleLink( $style, $options ) {
@@ -1924,7 +2004,7 @@ class OutputPage {
 
                if( isset( $options['dir'] ) ) {
                        global $wgContLang;
-                       $siteDir = $wgContLang->isRTL() ? 'rtl' : 'ltr';
+                       $siteDir = $wgContLang->getDir();
                        if( $siteDir != $options['dir'] )
                                return '';
                }
@@ -1935,7 +2015,7 @@ class OutputPage {
                                return '';
                        }
                } else {
-                       $media = '';
+                       $media = 'all';
                }
 
                if( substr( $style, 0, 1 ) == '/' ||
@@ -1947,15 +2027,7 @@ class OutputPage {
                        $url = $wgStylePath . '/' . $style . '?' . $wgStyleVersion;
                }
 
-               $attribs = array(
-                       'rel' => 'stylesheet',
-                       'href' => $url,
-                       'type' => 'text/css' );
-               if( $media ) {
-                       $attribs['media'] = $media;
-               }
-
-               $link = Xml::element( 'link', $attribs );
+               $link = Html::linkedStyle( $url, $media );
 
                if( isset( $options['condition'] ) ) {
                        $condition = htmlspecialchars( $options['condition'] );
@@ -2043,13 +2115,13 @@ class OutputPage {
         * @param int $lag Slave lag
         */
        public function showLagWarning( $lag ) {
-               global $wgSlaveLagWarning, $wgSlaveLagCritical;
+               global $wgSlaveLagWarning, $wgSlaveLagCritical, $wgLang;
                if( $lag >= $wgSlaveLagWarning ) {
                        $message = $lag < $wgSlaveLagCritical
                                ? 'lag-warn-normal'
                                : 'lag-warn-high';
-                       $warning = wfMsgExt( $message, 'parse', $lag );
-                       $this->addHTML( "<div class=\"mw-{$message}\">\n{$warning}\n</div>\n" );
+                       $wrap = Html::rawElement( 'div', array( 'class' => "mw-{$message}" ), "\n$1\n" );
+                       $this->wrapWikiMsg( "$wrap\n", array( $message, $wgLang->formatNum( $lag ) ) );
                }
        }