Merge "resourceloader: Allow style-only modules to have deprecation warnings"
[lhc/web/wiklou.git] / includes / resourceloader / ResourceLoaderClientHtml.php
index 6c4a5d0..479a263 100644 (file)
@@ -58,11 +58,15 @@ class ResourceLoaderClientHtml {
         * @param ResourceLoaderContext $context
         * @param array $options [optional] Array of options
         *  - 'target': Custom parameter passed to StartupModule.
+        *  - 'nonce': From OutputPage::getCSPNonce().
         */
        public function __construct( ResourceLoaderContext $context, array $options = [] ) {
                $this->context = $context;
                $this->resourceLoader = $context->getResourceLoader();
-               $this->options = $options;
+               $this->options = $options + [
+                       'target' => null,
+                       'nonce' => null,
+               ];
        }
 
        /**
@@ -139,7 +143,8 @@ class ResourceLoaderClientHtml {
                                'styles' => [],
                                'general' => [],
                        ],
-
+                       // Deprecations for style-only modules
+                       'styledeprecations' => [],
                ];
 
                foreach ( $this->modules as $name ) {
@@ -204,6 +209,10 @@ class ResourceLoaderClientHtml {
                                        $data['styles'][] = $name;
                                }
                        }
+                       $deprecation = $module->getDeprecationInformation();
+                       if ( $deprecation ) {
+                               $data['styledeprecations'][] = $deprecation;
+                       }
                }
 
                foreach ( $this->moduleScripts as $name ) {
@@ -251,6 +260,7 @@ class ResourceLoaderClientHtml {
         * @return string|WrappedStringList HTML
         */
        public function getHeadHtml() {
+               $nonce = $this->options['nonce'];
                $data = $this->getData();
                $chunks = [];
 
@@ -259,13 +269,15 @@ class ResourceLoaderClientHtml {
                // See also #getDocumentAttributes() and /resources/src/startup.js.
                $chunks[] = Html::inlineScript(
                        'document.documentElement.className = document.documentElement.className'
-                       . '.replace( /(^|\s)client-nojs(\s|$)/, "$1client-js$2" );'
+                       . '.replace( /(^|\s)client-nojs(\s|$)/, "$1client-js$2" );',
+                       $nonce
                );
 
                // Inline RLQ: Set page variables
                if ( $this->config ) {
                        $chunks[] = ResourceLoader::makeInlineScript(
-                               ResourceLoader::makeConfigSetScript( $this->config )
+                               ResourceLoader::makeConfigSetScript( $this->config ),
+                               $nonce
                        );
                }
 
@@ -273,7 +285,8 @@ class ResourceLoaderClientHtml {
                $states = array_merge( $this->exemptStates, $data['states'] );
                if ( $states ) {
                        $chunks[] = ResourceLoader::makeInlineScript(
-                               ResourceLoader::makeLoaderStateScript( $states )
+                               ResourceLoader::makeLoaderStateScript( $states ),
+                               $nonce
                        );
                }
 
@@ -281,14 +294,16 @@ class ResourceLoaderClientHtml {
                if ( $data['embed']['general'] ) {
                        $chunks[] = $this->getLoad(
                                $data['embed']['general'],
-                               ResourceLoaderModule::TYPE_COMBINED
+                               ResourceLoaderModule::TYPE_COMBINED,
+                               $nonce
                        );
                }
 
                // Inline RLQ: Load general modules
                if ( $data['general'] ) {
                        $chunks[] = ResourceLoader::makeInlineScript(
-                               Xml::encodeJsCall( 'mw.loader.load', [ $data['general'] ] )
+                               Xml::encodeJsCall( 'mw.loader.load', [ $data['general'] ] ),
+                               $nonce
                        );
                }
 
@@ -296,15 +311,25 @@ class ResourceLoaderClientHtml {
                if ( $data['scripts'] ) {
                        $chunks[] = $this->getLoad(
                                $data['scripts'],
-                               ResourceLoaderModule::TYPE_SCRIPTS
+                               ResourceLoaderModule::TYPE_SCRIPTS,
+                               $nonce
                        );
                }
 
-               // External stylesheets
+               // Deprecations for only=styles modules
+               if ( $data['styledeprecations'] ) {
+                       $chunks[] = ResourceLoader::makeInlineScript(
+                               implode( '', $data['styledeprecations'] ),
+                               $nonce
+                       );
+               }
+
+               // External stylesheets (only=styles)
                if ( $data['styles'] ) {
                        $chunks[] = $this->getLoad(
                                $data['styles'],
-                               ResourceLoaderModule::TYPE_STYLES
+                               ResourceLoaderModule::TYPE_STYLES,
+                               $nonce
                        );
                }
 
@@ -312,18 +337,20 @@ class ResourceLoaderClientHtml {
                if ( $data['embed']['styles'] ) {
                        $chunks[] = $this->getLoad(
                                $data['embed']['styles'],
-                               ResourceLoaderModule::TYPE_STYLES
+                               ResourceLoaderModule::TYPE_STYLES,
+                               $nonce
                        );
                }
 
                // Async scripts. Once the startup is loaded, inline RLQ scripts will run.
                // Pass-through a custom 'target' from OutputPage (T143066).
-               $startupQuery = isset( $this->options['target'] )
+               $startupQuery = $this->options['target'] !== null
                        ? [ 'target' => (string)$this->options['target'] ]
                        : [];
                $chunks[] = $this->getLoad(
                        'startup',
                        ResourceLoaderModule::TYPE_SCRIPTS,
+                       $nonce,
                        $startupQuery
                );
 
@@ -341,8 +368,8 @@ class ResourceLoaderClientHtml {
                return self::makeContext( $this->context, $group, $type );
        }
 
-       private function getLoad( $modules, $only, array $extraQuery = [] ) {
-               return self::makeLoad( $this->context, (array)$modules, $only, $extraQuery );
+       private function getLoad( $modules, $only, $nonce, array $extraQuery = [] ) {
+               return self::makeLoad( $this->context, (array)$modules, $only, $extraQuery, $nonce );
        }
 
        private static function makeContext( ResourceLoaderContext $mainContext, $group, $type,
@@ -358,7 +385,9 @@ class ResourceLoaderClientHtml {
                }
                $context = new ResourceLoaderContext( $mainContext->getResourceLoader(), $req );
                // Allow caller to setVersion() and setModules()
-               return new DerivativeResourceLoaderContext( $context );
+               $ret = new DerivativeResourceLoaderContext( $context );
+               $ret->setContentOverrideCallback( $mainContext->getContentOverrideCallback() );
+               return $ret;
        }
 
        /**
@@ -368,10 +397,11 @@ class ResourceLoaderClientHtml {
         * @param array $modules One or more module names
         * @param string $only ResourceLoaderModule TYPE_ class constant
         * @param array $extraQuery [optional] Array with extra query parameters for the request
+        * @param string $nonce [optional] Content-Security-Policy nonce (from OutputPage::getCSPNonce)
         * @return string|WrappedStringList HTML
         */
        public static function makeLoad( ResourceLoaderContext $mainContext, array $modules, $only,
-               array $extraQuery = []
+               array $extraQuery = [], $nonce = null
        ) {
                $rl = $mainContext->getResourceLoader();
                $chunks = [];
@@ -383,7 +413,7 @@ class ResourceLoaderClientHtml {
                        $chunks = [];
                        // Recursively call us for every item
                        foreach ( $modules as $name ) {
-                               $chunks[] = self::makeLoad( $mainContext, [ $name ], $only, $extraQuery );
+                               $chunks[] = self::makeLoad( $mainContext, [ $name ], $only, $extraQuery, $nonce );
                        }
                        return new WrappedStringList( "\n", $chunks );
                }
@@ -425,7 +455,8 @@ class ResourceLoaderClientHtml {
                                                        );
                                                } else {
                                                        $chunks[] = ResourceLoader::makeInlineScript(
-                                                               $rl->makeModuleResponse( $context, $moduleSet )
+                                                               $rl->makeModuleResponse( $context, $moduleSet ),
+                                                               $nonce
                                                        );
                                                }
                                        } else {
@@ -459,7 +490,8 @@ class ResourceLoaderClientHtml {
                                                                ] );
                                                        } else {
                                                                $chunk = ResourceLoader::makeInlineScript(
-                                                                       Xml::encodeJsCall( 'mw.loader.load', [ $url ] )
+                                                                       Xml::encodeJsCall( 'mw.loader.load', [ $url ] ),
+                                                                       $nonce
                                                                );
                                                        }
                                                }