Fix typo in comment
[lhc/web/wiklou.git] / includes / OutputPage.php
index 84fe1e9..beaca5f 100644 (file)
@@ -22,7 +22,7 @@ class OutputPage extends ContextSource {
        /// Should be private. Used with addMeta() which adds <meta>
        var $mMetatags = array();
 
-       /// <meta keyworkds="stuff"> most of the time the first 10 links to an article
+       /// <meta keywords="stuff"> most of the time the first 10 links to an article
        var $mKeywords = array();
 
        var $mLinktags = array();
@@ -813,7 +813,7 @@ class OutputPage extends ContextSource {
                $this->mPagetitle = $nameWithTags;
 
                # change "<i>foo&amp;bar</i>" to "foo&bar"
-               $this->setHTMLTitle( $this->msg( 'pagetitle', Sanitizer::stripAllTags( $nameWithTags ) ) );
+               $this->setHTMLTitle( $this->msg( 'pagetitle' )->rawParams( Sanitizer::stripAllTags( $nameWithTags ) ) );
        }
 
        /**
@@ -1075,7 +1075,7 @@ class OutputPage extends ContextSource {
        /**
         * Add new language links
         *
-        * @param $newLinkArray Associative array mapping language code to the page
+        * @param $newLinkArray array Associative array mapping language code to the page
         *                      name
         */
        public function addLanguageLinks( $newLinkArray ) {
@@ -1085,7 +1085,7 @@ class OutputPage extends ContextSource {
        /**
         * Reset the language links and add new language links
         *
-        * @param $newLinkArray Associative array mapping language code to the page
+        * @param $newLinkArray array Associative array mapping language code to the page
         *                      name
         */
        public function setLanguageLinks( $newLinkArray ) {
@@ -1208,9 +1208,11 @@ class OutputPage extends ContextSource {
         * Return whether user JavaScript is allowed for this page
         * @deprecated since 1.18 Load modules with ResourceLoader, and origin and
         *     trustworthiness is identified and enforced automagically.
+        *     Will be removed in 1.20.
         * @return Boolean
         */
        public function isUserJsAllowed() {
+               wfDeprecated( __METHOD__, '1.18' );
                return $this->getAllowedModules( ResourceLoaderModule::TYPE_SCRIPTS ) >= ResourceLoaderModule::ORIGIN_USER_INDIVIDUAL;
        }
 
@@ -1307,7 +1309,7 @@ class OutputPage extends ContextSource {
        /**
         * Get/set the ParserOptions object to use for wikitext parsing
         *
-        * @param $options either the ParserOption to use or null to only get the
+        * @param $options ParserOptions|null either the ParserOption to use or null to only get the
         *                 current ParserOption object
         * @return ParserOptions object
         */
@@ -1364,7 +1366,7 @@ class OutputPage extends ContextSource {
        /**
         * Set the displayed file version
         *
-        * @param $file File|false
+        * @param $file File|bool
         * @return Mixed: previous value
         */
        public function setFileVersion( $file ) {
@@ -1465,8 +1467,6 @@ class OutputPage extends ContextSource {
 
                wfProfileIn( __METHOD__ );
 
-               wfIncrStats( 'pcache_not_possible' );
-
                $popts = $this->parserOptions();
                $oldTidy = $popts->setTidy( $tidy );
                $popts->setInterfaceMessage( (bool) $interface );
@@ -2248,6 +2248,7 @@ class OutputPage extends ContextSource {
                        $params = array(
                                'id'   => 'wpTextbox1',
                                'name' => 'wpTextbox1',
+                               'cols' => $this->getUser()->getOption( 'cols' ),
                                'rows' => $this->getUser()->getOption( 'rows' ),
                                'readonly' => 'readonly',
                                'lang' => $pageLang->getHtmlCode(),
@@ -2343,7 +2344,7 @@ $templates
         * Add a "return to" link pointing to a specified title,
         * or the title indicated in the request, or else the main page
         *
-        * @param $unused No longer used
+        * @param $unused
         * @param $returnto Title or String to return to
         * @param $returntoquery String: query string for the return to link
         */
@@ -2379,6 +2380,7 @@ $templates
         */
        public function headElement( Skin $sk, $includeStyle = true ) {
                global $wgContLang;
+
                $userdir = $this->getLanguage()->getDir();
                $sitedir = $wgContLang->getDir();
 
@@ -2423,6 +2425,7 @@ $templates
                }
                $bodyAttrs['class'] .= ' ' . $sk->getPageClasses( $this->getTitle() );
                $bodyAttrs['class'] .= ' skin-' . Sanitizer::escapeClass( $sk->getSkinName() );
+               $bodyAttrs['class'] .= ' action-' . Sanitizer::escapeClass( Action::getActionName( $this->getContext() ) );
 
                $sk->addToBodyAttributes( $this, $bodyAttrs ); // Allow skins to add body attributes they need
                wfRunHooks( 'OutputPageBodyAttributes', array( $this, $sk, &$bodyAttrs ) );
@@ -2436,12 +2439,12 @@ $templates
         * Add the default ResourceLoader modules to this object
         */
        private function addDefaultModules() {
-               global $wgIncludeLegacyJavaScript, $wgUseAjax, $wgAjaxWatch, $wgEnableMWSuggest;
+               global $wgIncludeLegacyJavaScript, $wgPreloadJavaScriptMwUtil, $wgUseAjax,
+                       $wgAjaxWatch, $wgEnableMWSuggest;
 
                // Add base resources
                $this->addModules( array(
                        'mediawiki.user',
-                       'mediawiki.util',
                        'mediawiki.page.startup',
                        'mediawiki.page.ready',
                ) );
@@ -2449,6 +2452,12 @@ $templates
                        $this->addModules( 'mediawiki.legacy.wikibits' );
                }
 
+               if ( $wgPreloadJavaScriptMwUtil ) {
+                       $this->addModules( 'mediawiki.util' );
+               }
+
+               MWDebug::addModules( $this );
+
                // Add various resources if required
                if ( $wgUseAjax ) {
                        $this->addModules( 'mediawiki.legacy.ajax' );
@@ -2492,10 +2501,11 @@ $templates
         * @param $only String ResourceLoaderModule TYPE_ class constant
         * @param $useESI boolean
         * @param $extraQuery Array with extra query parameters to add to each request. array( param => value )
+        * @param $loadCall boolean If true, output an (asynchronous) mw.loader.load() call rather than a <script src="..."> tag
         * @return string html <script> and <style> tags
         */
-       protected function makeResourceLoaderLink( $modules, $only, $useESI = false, array $extraQuery = array() ) {
-               global $wgResourceLoaderUseESI, $wgResourceLoaderInlinePrivateModules;
+       protected function makeResourceLoaderLink( $modules, $only, $useESI = false, array $extraQuery = array(), $loadCall = false ) {
+               global $wgResourceLoaderUseESI;
 
                if ( !count( $modules ) ) {
                        return '';
@@ -2574,10 +2584,11 @@ $templates
                                continue;
                        }
 
-                       // Support inlining of private modules if configured as such. Note that these
-                       // modules should be loaded from getHeadScripts() before the first loader call.
-                       // Otherwise other modules can't properly use them as dependencies (bug 30914)
-                       if ( $group === 'private' && $wgResourceLoaderInlinePrivateModules ) {
+                       // Inline private modules. These can't be loaded through load.php for security
+                       // reasons, see bug 34907. Note that these modules should be loaded from
+                       // getHeadScripts() before the first loader call. Otherwise other modules can't
+                       // properly use them as dependencies (bug 30914)
+                       if ( $group === 'private' ) {
                                if ( $only == ResourceLoaderModule::TYPE_STYLES ) {
                                        $links .= Html::inlineStyle(
                                                $resourceLoader->makeModuleResponse( $context, $modules )
@@ -2631,6 +2642,12 @@ $templates
                                // Automatically select style/script elements
                                if ( $only === ResourceLoaderModule::TYPE_STYLES ) {
                                        $link = Html::linkedStyle( $url );
+                               } else if ( $loadCall ) { 
+                                       $link = Html::inlineScript(
+                                               ResourceLoader::makeLoaderConditionalScript(
+                                                       Xml::encodeJsCall( 'mw.loader.load', array( $url, 'text/javascript', true ) )
+                                               )
+                                       );
                                } else {
                                        $link = Html::linkedScript( $url );
                                }
@@ -2652,6 +2669,8 @@ $templates
         * @return String: HTML fragment
         */
        function getHeadScripts() {
+               global $wgResourceLoaderExperimentalAsyncLoading;
+               
                // Startup - this will immediately load jquery and mediawiki modules
                $scripts = $this->makeResourceLoaderLink( 'startup', ResourceLoaderModule::TYPE_SCRIPTS, true );
 
@@ -2663,6 +2682,8 @@ $templates
                );
 
                // Load embeddable private modules before any loader links
+               // This needs to be TYPE_COMBINED so these modules are properly wrapped
+               // in mw.loader.implement() calls and deferred until mw.user is available
                $embedScripts = array( 'user.options', 'user.tokens' );
                $scripts .= $this->makeResourceLoaderLink( $embedScripts, ResourceLoaderModule::TYPE_COMBINED );
 
@@ -2681,23 +2702,37 @@ $templates
                                )
                        );
                }
+               
+               if ( $wgResourceLoaderExperimentalAsyncLoading ) {
+                       $scripts .= $this->getScriptsForBottomQueue( true );
+               }
 
                return $scripts;
        }
 
        /**
-        * JS stuff to put at the bottom of the <body>: modules marked with position 'bottom',
-        * legacy scripts ($this->mScripts), user preferences, site JS and user JS
+        * JS stuff to put at the 'bottom', which can either be the bottom of the <body>
+        * or the bottom of the <head> depending on $wgResourceLoaderExperimentalAsyncLoading:
+        * modules marked with position 'bottom', legacy scripts ($this->mScripts),
+        * user preferences, site JS and user JS
         *
+        * @param $inHead boolean If true, this HTML goes into the <head>, if false it goes into the <body>
         * @return string
         */
-       function getBottomScripts() {
+       function getScriptsForBottomQueue( $inHead ) {
                global $wgUseSiteJs, $wgAllowUserJs;
 
                // Script and Messages "only" requests marked for bottom inclusion
+               // If we're in the <head>, use load() calls rather than <script src="..."> tags
                // Messages should go first
-               $scripts = $this->makeResourceLoaderLink( $this->getModuleMessages( true, 'bottom' ), ResourceLoaderModule::TYPE_MESSAGES );
-               $scripts .= $this->makeResourceLoaderLink( $this->getModuleScripts( true, 'bottom' ), ResourceLoaderModule::TYPE_SCRIPTS );
+               $scripts = $this->makeResourceLoaderLink( $this->getModuleMessages( true, 'bottom' ),
+                       ResourceLoaderModule::TYPE_MESSAGES, /* $useESI = */ false, /* $extraQuery = */ array(),
+                       /* $loadCall = */ $inHead
+               );
+               $scripts .= $this->makeResourceLoaderLink( $this->getModuleScripts( true, 'bottom' ),
+                       ResourceLoaderModule::TYPE_SCRIPTS, /* $useESI = */ false, /* $extraQuery = */ array(),
+                       /* $loadCall = */ $inHead
+               );
 
                // Modules requests - let the client calculate dependencies and batch requests as it likes
                // Only load modules that have marked themselves for loading at the bottom
@@ -2705,7 +2740,7 @@ $templates
                if ( $modules ) {
                        $scripts .= Html::inlineScript(
                                ResourceLoader::makeLoaderConditionalScript(
-                                       Xml::encodeJsCall( 'mw.loader.load', array( $modules ) )
+                                       Xml::encodeJsCall( 'mw.loader.load', array( $modules, null, true ) )
                                )
                        );
                }
@@ -2717,7 +2752,9 @@ $templates
 
                // Add site JS if enabled
                if ( $wgUseSiteJs ) {
-                       $scripts .= $this->makeResourceLoaderLink( 'site', ResourceLoaderModule::TYPE_SCRIPTS );
+                       $scripts .= $this->makeResourceLoaderLink( 'site', ResourceLoaderModule::TYPE_SCRIPTS,
+                               /* $useESI = */ false, /* $extraQuery = */ array(), /* $loadCall = */ $inHead
+                       );
                        if( $this->getUser()->isLoggedIn() ){
                                $userScripts[] = 'user.groups';
                        }
@@ -2730,7 +2767,7 @@ $templates
                                // We're on a preview of a JS subpage
                                // Exclude this page from the user module in case it's in there (bug 26283)
                                $scripts .= $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_SCRIPTS, false,
-                                       array( 'excludepage' => $this->getTitle()->getPrefixedDBkey() )
+                                       array( 'excludepage' => $this->getTitle()->getPrefixedDBkey() ), $inHead
                                );
                                // Load the previewed JS
                                $scripts .= Html::inlineScript( "\n" . $this->getRequest()->getText( 'wpTextbox1' ) . "\n" ) . "\n";
@@ -2738,14 +2775,31 @@ $templates
                                // Include the user module normally
                                // We can't do $userScripts[] = 'user'; because the user module would end up
                                // being wrapped in a closure, so load it raw like 'site'
-                               $scripts .= $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_SCRIPTS );
+                               $scripts .= $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_SCRIPTS,
+                                       /* $useESI = */ false, /* $extraQuery = */ array(), /* $loadCall = */ $inHead
+                               );
                        }
                }
-               $scripts .= $this->makeResourceLoaderLink( $userScripts, ResourceLoaderModule::TYPE_COMBINED );
+               $scripts .= $this->makeResourceLoaderLink( $userScripts, ResourceLoaderModule::TYPE_COMBINED,
+                       /* $useESI = */ false, /* $extraQuery = */ array(), /* $loadCall = */ $inHead
+               );
 
                return $scripts;
        }
 
+       /**
+        * JS stuff to put at the bottom of the <body>
+        * @return string
+        */
+       function getBottomScripts() {
+               global $wgResourceLoaderExperimentalAsyncLoading;
+               if ( !$wgResourceLoaderExperimentalAsyncLoading ) {
+                       return $this->getScriptsForBottomQueue( false );
+               } else {
+                       return '';
+               }
+       }
+
        /**
         * Add one or more variables to be set in mw.config in JavaScript.
         *
@@ -2777,15 +2831,26 @@ $templates
         * @return array
         */
        public function getJSVars() {
-               global $wgUseAjax, $wgEnableMWSuggest;
+               global $wgUseAjax, $wgEnableMWSuggest, $wgContLang;
+
+               $latestRevID = 0;
+               $pageID = 0;
+               $canonicalName = false; # bug 21115
 
                $title = $this->getTitle();
                $ns = $title->getNamespace();
                $nsname = MWNamespace::exists( $ns ) ? MWNamespace::getCanonicalName( $ns ) : $title->getNsText();
+
+               // Get the relevant title so that AJAX features can use the correct page name
+               // when making API requests from certain special pages (bug 34972).
+               $relevantTitle = $this->getSkin()->getRelevantTitle();
+
                if ( $ns == NS_SPECIAL ) {
                        list( $canonicalName, /*...*/ ) = SpecialPageFactory::resolveAlias( $title->getDBkey() );
-               } else {
-                       $canonicalName = false; # bug 21115
+               } elseif ( $this->canUseWikiPage() ) {
+                       $wikiPage = $this->getWikiPage();
+                       $latestRevID = $wikiPage->getLatest();
+                       $pageID = $wikiPage->getId();
                }
 
                $lang = $title->getPageLanguage();
@@ -2810,10 +2875,10 @@ $templates
                        'wgNamespaceNumber' => $title->getNamespace(),
                        'wgPageName' => $title->getPrefixedDBKey(),
                        'wgTitle' => $title->getText(),
-                       'wgCurRevisionId' => $title->getLatestRevID(),
-                       'wgArticleId' => $title->getArticleId(),
+                       'wgCurRevisionId' => $latestRevID,
+                       'wgArticleId' => $pageID,
                        'wgIsArticle' => $this->isArticle(),
-                       'wgAction' => $this->getRequest()->getText( 'action', 'view' ),
+                       'wgAction' => Action::getActionName( $this->getContext() ),
                        'wgUserName' => $this->getUser()->isAnon() ? null : $this->getUser()->getName(),
                        'wgUserGroups' => $this->getUser()->getEffectiveGroups(),
                        'wgCategories' => $this->getCategories(),
@@ -2821,9 +2886,10 @@ $templates
                        'wgPageContentLanguage' => $lang->getCode(),
                        'wgSeparatorTransformTable' => $compactSeparatorTransTable,
                        'wgDigitTransformTable' => $compactDigitTransTable,
+                       'wgRelevantPageName' => $relevantTitle->getPrefixedDBKey(),
                );
-               if ( $lang->hasVariants() ) {
-                       $vars['wgUserVariant'] = $lang->getPreferredVariant();
+               if ( $wgContLang->hasVariants() ) {
+                       $vars['wgUserVariant'] = $wgContLang->getPreferredVariant();
                }
                foreach ( $title->getRestrictionTypes() as $type ) {
                        $vars['wgRestriction' . ucfirst( $type )] = $title->getRestrictions( $type );
@@ -2873,7 +2939,7 @@ $templates
        }
 
        /**
-        * @param $unused Unused
+        * @param $unused
         * @param $addContentType bool
         *
         * @return string HTML tag links to be put in the header.
@@ -3164,7 +3230,8 @@ $templates
         * @return string
         */
        public function buildCssLinks() {
-               global $wgUseSiteCss, $wgAllowUserCss, $wgAllowUserCssPrefs;
+               global $wgUseSiteCss, $wgAllowUserCss, $wgAllowUserCssPrefs,
+                       $wgLang, $wgContLang;
 
                $this->getSkin()->setupSkinUserCss( $this );
 
@@ -3193,8 +3260,15 @@ $templates
                                $otherTags .= $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_STYLES, false,
                                        array( 'excludepage' => $this->getTitle()->getPrefixedDBkey() )
                                );
+                               
                                // Load the previewed CSS
-                               $this->addInlineStyle( $this->getRequest()->getText( 'wpTextbox1' ) );
+                               // If needed, Janus it first. This is user-supplied CSS, so it's
+                               // assumed to be right for the content language directionality.
+                               $previewedCSS = $this->getRequest()->getText( 'wpTextbox1' );
+                               if ( $wgLang->getDir() !== $wgContLang->getDir() ) {
+                                       $previewedCSS = CSSJanus::transform( $previewedCSS, true, false );
+                               }
+                               $otherTags .= Html::inlineStyle( $previewedCSS );
                        } else {
                                // Load the user styles normally
                                $moduleStyles[] = 'user';
@@ -3203,7 +3277,7 @@ $templates
 
                // Per-user preference styles
                if ( $wgAllowUserCssPrefs ) {
-                       $moduleStyles[] = 'user.options';
+                       $moduleStyles[] = 'user.cssprefs';
                }
 
                foreach ( $moduleStyles as $name ) {
@@ -3365,7 +3439,7 @@ $templates
         * @param $args array
         */
        public function addWikiMsgArray( $name, $args ) {
-               $this->addWikiText( $this->msg( $name, $args )->plain() );
+               $this->addHTML( $this->msg( $name, $args )->parseAsBlock() );
        }
 
        /**