X-Git-Url: https://git.heureux-cyclage.org/?p=lhc%2Fweb%2Fwiklou.git;a=blobdiff_plain;f=includes%2Fresourceloader%2FResourceLoader.php;h=54ab6a12421b2ee0fe7db60e36b6f2d85c608207;hp=ca83ff357d011e36d5589e59337ff6f58ce31836;hb=1b32592d9c64226226bf77baff4b1be944db2697;hpb=cdeb7109f223729fb8fc38e49bf03ac77b747c05 diff --git a/includes/resourceloader/ResourceLoader.php b/includes/resourceloader/ResourceLoader.php index ca83ff357d..54ab6a1242 100644 --- a/includes/resourceloader/ResourceLoader.php +++ b/includes/resourceloader/ResourceLoader.php @@ -1,7 +1,5 @@ . + */ + +/** + * ResourceLoader is a loading system for JavaScript and CSS resources. + * + * For higher level documentation, see . * - * Most of the documentation is on the MediaWiki documentation wiki starting at: - * https://www.mediawiki.org/wiki/ResourceLoader + * @ingroup ResourceLoader + * @since 1.17 */ class ResourceLoader implements LoggerAwareInterface { - /** @var Config $config */ + /** @var Config */ protected $config; /** @var MessageBlobStore */ protected $blobStore; @@ -683,24 +689,29 @@ class ResourceLoader implements LoggerAwareInterface { * * @since 1.28 * @param ResourceLoaderContext $context + * @param string[]|null $modules * @return string Hash */ - public function makeVersionQuery( ResourceLoaderContext $context ) { + public function makeVersionQuery( ResourceLoaderContext $context, array $modules = null ) { + if ( $modules === null ) { + wfDeprecated( __METHOD__ . ' without $modules', '1.34' ); + $modules = $context->getModules(); + } // As of MediaWiki 1.28, the server and client use the same algorithm for combining // version hashes. There is no technical reason for this to be same, and for years the // implementations differed. If getCombinedVersion in PHP (used for StartupModule and // E-Tag headers) differs in the future from getCombinedVersion in JS (used for 'version' // query parameter), then this method must continue to match the JS one. - $moduleNames = []; - foreach ( $context->getModules() as $name ) { + $filtered = []; + foreach ( $modules as $name ) { if ( !$this->getModule( $name ) ) { // If a versioned request contains a missing module, the version is a mismatch // as the client considered a module (and version) we don't have. return ''; } - $moduleNames[] = $name; + $filtered[] = $name; } - return $this->getCombinedVersion( $context, $moduleNames ); + return $this->getCombinedVersion( $context, $filtered ); } /** @@ -812,9 +823,9 @@ class ResourceLoader implements LoggerAwareInterface { $errorText = implode( "\n\n", $this->errors ); $errorResponse = self::makeComment( $errorText ); if ( $context->shouldIncludeScripts() ) { - $errorResponse .= 'if (window.console && console.error) {' - . Xml::encodeJsCall( 'console.error', [ $errorText ] ) - . "}\n"; + $errorResponse .= 'if (window.console && console.error) { console.error(' + . $context->encodeJson( $errorText ) + . "); }\n"; } // Prepend error info to the response @@ -857,7 +868,7 @@ class ResourceLoader implements LoggerAwareInterface { // - Version mismatch (T117587, T47877) if ( is_null( $context->getVersion() ) || $errors - || $context->getVersion() !== $this->makeVersionQuery( $context ) + || $context->getVersion() !== $this->makeVersionQuery( $context, $context->getModules() ) ) { $maxage = $rlMaxage['unversioned']['client']; $smaxage = $rlMaxage['unversioned']['server']; @@ -1087,7 +1098,14 @@ MESSAGE; $strContent = $scripts; } elseif ( is_array( $scripts ) ) { // ...except when $scripts is an array of URLs or an associative array - $strContent = self::makeLoaderImplementScript( $implementKey, $scripts, [], [], [] ); + $strContent = self::makeLoaderImplementScript( + $context, + $implementKey, + $scripts, + [], + [], + [] + ); } break; case 'styles': @@ -1113,6 +1131,7 @@ MESSAGE; } } $strContent = self::makeLoaderImplementScript( + $context, $implementKey, $scripts, $content['styles'] ?? [], @@ -1158,7 +1177,7 @@ MESSAGE; // Set the state of modules we didn't respond to with mw.loader.implement if ( $states ) { - $stateScript = self::makeLoaderStateScript( $states ); + $stateScript = self::makeLoaderStateScript( $context, $states ); if ( !$context->getDebug() ) { $stateScript = self::filter( 'minify-js', $stateScript ); } @@ -1167,7 +1186,7 @@ MESSAGE; } } elseif ( $states ) { $this->errors[] = 'Problematic modules: ' - . self::encodeJsonForScript( $states ); + . $context->encodeJson( $states ); } return $out; @@ -1206,6 +1225,7 @@ MESSAGE; /** * Return JS code that calls mw.loader.implement with given module properties. * + * @param ResourceLoaderContext $context * @param string $name Module name or implement key (format "`[name]@[version]`") * @param XmlJsCode|array|string $scripts Code as XmlJsCode (to be wrapped in a closure), * list of URLs to JavaScript files, string of JavaScript for `$.globalEval`, or array with @@ -1220,13 +1240,13 @@ MESSAGE; * @throws MWException * @return string JavaScript code */ - protected static function makeLoaderImplementScript( - $name, $scripts, $styles, $messages, $templates + private static function makeLoaderImplementScript( + ResourceLoaderContext $context, $name, $scripts, $styles, $messages, $templates ) { if ( $scripts instanceof XmlJsCode ) { if ( $scripts->value === '' ) { $scripts = null; - } elseif ( self::inDebugMode() ) { + } elseif ( $context->getDebug() ) { $scripts = new XmlJsCode( "function ( $, jQuery, require, module ) {\n{$scripts->value}\n}" ); } else { $scripts = new XmlJsCode( 'function($,jQuery,require,module){' . $scripts->value . '}' ); @@ -1238,7 +1258,7 @@ MESSAGE; // All of these essentially do $file = $file['content'];, some just have wrapping around it if ( $file['type'] === 'script' ) { // Multi-file modules only get two parameters ($ and jQuery are being phased out) - if ( self::inDebugMode() ) { + if ( $context->getDebug() ) { $file = new XmlJsCode( "function ( require, module ) {\n{$file['content']}\n}" ); } else { $file = new XmlJsCode( 'function(require,module){' . $file['content'] . '}' ); @@ -1249,8 +1269,8 @@ MESSAGE; } $scripts = XmlJsCode::encodeObject( [ 'main' => $scripts['main'], - 'files' => XmlJsCode::encodeObject( $files, self::inDebugMode() ) - ], self::inDebugMode() ); + 'files' => XmlJsCode::encodeObject( $files, $context->getDebug() ) + ], $context->getDebug() ); } elseif ( !is_string( $scripts ) && !is_array( $scripts ) ) { throw new MWException( 'Invalid scripts error. Array of URLs or string of code expected.' ); } @@ -1267,14 +1287,13 @@ MESSAGE; ]; self::trimArray( $module ); - return Xml::encodeJsCall( 'mw.loader.implement', $module, self::inDebugMode() ); + return Xml::encodeJsCall( 'mw.loader.implement', $module, $context->getDebug() ); } /** * Returns JS code which, when called, will register a given list of messages. * - * @param mixed $messages Either an associative array mapping message key to value, or a - * JSON-encoded message blob containing the same data, wrapped in an XmlJsCode object. + * @param mixed $messages Associative array mapping message key to value. * @return string JavaScript code */ public static function makeMessageSetScript( $messages ) { @@ -1323,8 +1342,8 @@ MESSAGE; * * @internal * @since 1.32 - * @param bool|string|array $data - * @return string JSON + * @param mixed $data + * @return string|false JSON string, false on error */ public static function encodeJsonForScript( $data ) { // Keep output as small as possible by disabling needless escape modes @@ -1347,25 +1366,22 @@ MESSAGE; } /** - * Returns a JS call to mw.loader.state, which sets the state of one - * ore more modules to a given value. Has two calling conventions: - * - * - ResourceLoader::makeLoaderStateScript( $name, $state ): - * Set the state of a single module called $name to $state + * Returns a JS call to mw.loader.state, which sets the state of modules + * to a given value: * - * - ResourceLoader::makeLoaderStateScript( [ $name => $state, ... ] ): + * - ResourceLoader::makeLoaderStateScript( $context, [ $name => $state, ... ] ): * Set the state of modules with the given names to the given states * - * @param array|string $states - * @param string|null $state + * @internal + * @param ResourceLoaderContext $context + * @param array $states * @return string JavaScript code */ - public static function makeLoaderStateScript( $states, $state = null ) { - if ( !is_array( $states ) ) { - $states = [ $states => $state ]; - } + public static function makeLoaderStateScript( + ResourceLoaderContext $context, array $states + ) { return 'mw.loader.state(' - . self::encodeJsonForScript( $states ) + . $context->encodeJson( $states ) . ');'; } @@ -1410,15 +1426,15 @@ MESSAGE; * @par Example * @code * - * ResourceLoader::makeLoaderRegisterScript( [ + * ResourceLoader::makeLoaderRegisterScript( $context, [ * [ $name1, $version1, $dependencies1, $group1, $source1, $skip1 ], * [ $name2, $version2, $dependencies1, $group2, $source2, $skip2 ], * ... * ] ): * @endcode * - * @internal - * @since 1.32 + * @internal For use by ResourceLoaderStartUpModule only + * @param ResourceLoaderContext $context * @param array $modules Array of module registration arrays, each containing * - string: module name * - string: module version @@ -1428,7 +1444,9 @@ MESSAGE; * - string|null: Script body of a skip function (optional) * @return string JavaScript code */ - public static function makeLoaderRegisterScript( array $modules ) { + public static function makeLoaderRegisterScript( + ResourceLoaderContext $context, array $modules + ) { // Optimisation: Transform dependency names into indexes when possible // to produce smaller output. They are expanded by mw.loader.register on // the other end using resolveIndexedDependencies(). @@ -1451,30 +1469,29 @@ MESSAGE; array_walk( $modules, [ self::class, 'trimArray' ] ); return 'mw.loader.register(' - . self::encodeJsonForScript( $modules ) + . $context->encodeJson( $modules ) . ');'; } /** * Returns JS code which calls mw.loader.addSource() with the given - * parameters. Has two calling conventions: - * - * - ResourceLoader::makeLoaderSourcesScript( $id, $properties ): - * Register a single source + * parameters. * - * - ResourceLoader::makeLoaderSourcesScript( [ $id1 => $loadUrl, $id2 => $loadUrl, ... ] ); + * - ResourceLoader::makeLoaderSourcesScript( $context, + * [ $id1 => $loadUrl, $id2 => $loadUrl, ... ] + * ); * Register sources with the given IDs and properties. * - * @param string|array $sources Source ID - * @param string|null $loadUrl load.php url + * @internal For use by ResourceLoaderStartUpModule only + * @param ResourceLoaderContext $context + * @param array $sources * @return string JavaScript code */ - public static function makeLoaderSourcesScript( $sources, $loadUrl = null ) { - if ( !is_array( $sources ) ) { - $sources = [ $sources => $loadUrl ]; - } + public static function makeLoaderSourcesScript( + ResourceLoaderContext $context, array $sources + ) { return 'mw.loader.addSource(' - . self::encodeJsonForScript( $sources ) + . $context->encodeJson( $sources ) . ');'; } @@ -1545,20 +1562,16 @@ MESSAGE; * @throws Exception */ public static function makeConfigSetScript( array $configuration ) { - $js = Xml::encodeJsCall( - 'mw.config.set', - [ $configuration ], - self::inDebugMode() - ); - if ( $js === false ) { + $json = self::encodeJsonForScript( $configuration ); + if ( $json === false ) { $e = new Exception( 'JSON serialization of config data failed. ' . 'This usually means the config data is not valid UTF-8.' ); MWExceptionHandler::logException( $e ); - $js = Xml::encodeJsCall( 'mw.log.error', [ $e->__toString() ] ); + return 'mw.log.error(' . self::encodeJsonForScript( $e->__toString() ) . ');'; } - return $js; + return "mw.config.set($json);"; } /** @@ -1804,10 +1817,11 @@ MESSAGE; * Get global LESS variables. * * @since 1.27 - * @deprecated since 1.32 Use ResourceLoderModule::getLessVars() instead. + * @deprecated since 1.32 Use ResourceLoaderModule::getLessVars() instead. * @return array Map of variable names to string CSS values. */ public function getLessVars() { + wfDeprecated( __METHOD__, '1.32' ); return []; } }