24use Psr\Log\LoggerAwareInterface;
25use Psr\Log\LoggerInterface;
26use Psr\Log\NullLogger;
28use Wikimedia\WrappedString;
56 protected $moduleInfos = [];
62 protected $testModuleNames = [];
64 protected $testSuiteModuleNames = [];
67 protected $sources = [];
69 protected $errors = [];
71 protected $extraHeaders = [];
74 protected static $debugMode =
null;
77 const CACHE_VERSION = 8;
80 const FILTER_NOMIN =
'/*@nomin*/';
97 if ( !$moduleNames ) {
106 $res =
$dbr->select(
'module_deps', [
'md_module',
'md_deps' ], [
107 'md_module' => $moduleNames,
113 $modulesWithDeps = [];
114 foreach (
$res as $row ) {
115 $module = $this->
getModule( $row->md_module );
118 json_decode( $row->md_deps,
true )
120 $modulesWithDeps[] = $row->md_module;
124 foreach ( array_diff( $moduleNames, $modulesWithDeps ) as $name ) {
132 ResourceLoaderWikiModule::preloadTitleInfo(
$context,
$dbr, $moduleNames );
136 foreach ( $moduleNames as $name ) {
138 if ( $module && $module->getMessages() ) {
144 foreach ( $blobs as $name =>
$blob ) {
167 if ( strpos( $data, self::FILTER_NOMIN ) !==
false ) {
171 if ( isset( $options[
'cache'] ) && $options[
'cache'] ===
false ) {
172 return self::applyFilter(
$filter, $data );
175 $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
178 $key =
$cache->makeGlobalKey(
179 'resourceloader-filter',
185 $result =
$cache->get( $key );
186 if ( $result ===
false ) {
187 $stats->increment(
"resourceloader_cache.$filter.miss" );
188 $result = self::applyFilter(
$filter, $data );
189 $cache->set( $key, $result, 24 * 3600 );
191 $stats->increment(
"resourceloader_cache.$filter.hit" );
193 if ( $result ===
null ) {
202 $data = trim( $data );
205 $data = (
$filter ===
'minify-css' )
206 ? CSSMin::minify( $data )
208 }
catch ( Exception $e ) {
209 MWExceptionHandler::logException( $e );
222 $this->logger = $logger ?:
new NullLogger();
225 wfDeprecated( __METHOD__ .
' without a Config instance',
'1.34' );
226 $config = MediaWikiServices::getInstance()->getMainConfig();
228 $this->config = $config;
231 $this->
addSource(
'local', $config->
get(
'LoadScript' ) );
234 $this->
register(
'startup', [
'class' => ResourceLoaderStartUpModule::class ] );
243 return $this->config;
251 $this->logger = $logger;
259 return $this->logger;
267 return $this->blobStore;
275 $this->blobStore = $blobStore;
289 public function register( $name, $info = null ) {
290 $moduleSkinStyles = $this->config->get(
'ResourceModuleSkinStyles' );
293 $registrations = is_array( $name ) ? $name : [ $name => $info ];
294 foreach ( $registrations as $name => $info ) {
296 if ( isset( $this->moduleInfos[$name] ) ) {
298 $this->logger->warning(
299 'ResourceLoader duplicate registration warning. ' .
300 'Another module has already been registered as ' . $name
305 if ( !self::isValidModuleName( $name ) ) {
306 throw new MWException(
"ResourceLoader module name '$name' is invalid, "
307 .
"see ResourceLoader::isValidModuleName()" );
309 if ( !is_array( $info ) ) {
310 throw new InvalidArgumentException(
311 'Invalid module info for "' . $name .
'": expected array, got ' . gettype( $info )
316 $this->moduleInfos[$name] = $info;
321 foreach ( $moduleSkinStyles as $skinName => $skinStyles ) {
323 if ( isset( $this->moduleInfos[$name][
'skinStyles'][$skinName] ) ) {
329 if ( isset( $skinStyles[$name] ) ) {
330 $paths = (array)$skinStyles[$name];
332 } elseif ( isset( $skinStyles[
'+' . $name] ) ) {
333 $paths = (array)$skinStyles[
'+' . $name];
334 $styleFiles = isset( $this->moduleInfos[$name][
'skinStyles'][
'default'] ) ?
335 (array)$this->moduleInfos[$name][
'skinStyles'][
'default'] :
343 list( $localBasePath, $remoteBasePath ) =
344 ResourceLoaderFileModule::extractBasePaths( $skinStyles );
346 foreach ( $paths as
$path ) {
350 $this->moduleInfos[$name][
'skinStyles'][$skinName] = $styleFiles;
363 if ( $this->config->get(
'EnableJavaScriptTest' ) !==
true ) {
364 throw new MWException(
'Attempt to register JavaScript test modules '
365 .
'but <code>$wgEnableJavaScriptTest</code> is false. '
366 .
'Edit your <code>LocalSettings.php</code> to enable it.' );
370 $testModulesMeta = [
'qunit' => [] ];
375 Hooks::run(
'ResourceLoaderTestModules', [ &$testModulesMeta, &$rl ] );
376 $extRegistry = ExtensionRegistry::getInstance();
378 $testModules = $testModulesMeta[
'qunit'] + $extRegistry->getAttribute(
'QUnitTestModules' );
380 $testSuiteModuleNames = [];
381 foreach ( $testModules as $name => &$module ) {
383 if ( isset( $module[
'dependencies'] ) && is_string( $module[
'dependencies'] ) ) {
384 $module[
'dependencies'] = [ $module[
'dependencies'] ];
388 $module[
'dependencies'][] =
'test.mediawiki.qunit.testrunner';
391 $testSuiteModuleNames[] = $name;
395 $testModules = ( include
"$IP/tests/qunit/QUnitTestResources.php" ) + $testModules;
396 $testSuiteModuleNames[] =
'test.mediawiki.qunit.suites';
398 $this->
register( $testModules );
399 $this->testSuiteModuleNames = $testSuiteModuleNames;
414 if ( is_array( $id ) ) {
415 foreach ( $id as $key => $value ) {
422 if ( isset( $this->sources[$id] ) ) {
424 'ResourceLoader duplicate source addition error. ' .
425 'Another source has already been registered as ' . $id
430 if ( is_array( $loadUrl ) ) {
431 if ( !isset( $loadUrl[
'loadScript'] ) ) {
433 __METHOD__ .
' was passed an array with no "loadScript" key.'
437 $loadUrl = $loadUrl[
'loadScript'];
440 $this->sources[$id] = $loadUrl;
449 return array_keys( $this->moduleInfos );
460 return $this->testSuiteModuleNames;
471 return isset( $this->moduleInfos[$name] );
486 if ( !isset( $this->modules[$name] ) ) {
487 if ( !isset( $this->moduleInfos[$name] ) ) {
492 $info = $this->moduleInfos[$name];
493 if ( isset( $info[
'factory'] ) ) {
495 $object = call_user_func( $info[
'factory'], $info );
497 $class = $info[
'class'] ?? ResourceLoaderFileModule::class;
499 $object =
new $class( $info );
501 $object->setConfig( $this->
getConfig() );
502 $object->setLogger( $this->logger );
503 $object->setName( $name );
504 $this->modules[$name] = $object;
507 return $this->modules[$name];
517 if ( !isset( $this->moduleInfos[$name] ) ) {
520 $info = $this->moduleInfos[$name];
521 return !isset( $info[
'factory'] ) && (
523 !isset( $info[
'class'] ) ||
525 $info[
'class'] === ResourceLoaderFileModule::class ||
526 is_subclass_of( $info[
'class'], ResourceLoaderFileModule::class )
536 return $this->sources;
549 if ( !isset( $this->sources[
$source] ) ) {
550 throw new MWException(
"The $source source was never registered in ResourceLoader." );
552 return $this->sources[
$source];
623 $hash = hash(
'fnv132', $value );
627 Wikimedia\base_convert( $hash, 16, 36, self::HASH_LENGTH ),
643 MWExceptionHandler::logException( $e );
644 $this->logger->warning(
648 $this->errors[] = self::formatExceptionNoComment( $e );
660 if ( !$moduleNames ) {
666 }
catch ( Exception $e ) {
670 'Calculating version for "{module}" failed: {exception}',
678 return self::makeHash( implode(
'',
$hashes ) );
697 wfDeprecated( __METHOD__ .
' without $modules',
'1.34' );
737 foreach (
$context->getModules() as $name ) {
742 if ( $module->getGroup() ===
'private' ) {
744 $this->logger->debug(
"Request for private module '$name' denied" );
745 $this->errors[] =
"Cannot build private module \"$name\"";
757 }
catch ( Exception $e ) {
765 }
catch ( Exception $e ) {
771 $etag =
'W/"' . $versionHash .
'"';
779 if ( $this->config->get(
'UseFileCache' ) ) {
794 $warnings = ob_get_contents();
795 if ( strlen( $warnings ) ) {
796 $this->errors[] = $warnings;
806 if ( $fileCache->isCacheWorthy() ) {
810 $fileCache->incrMissesRecent(
$context->getRequest() );
819 if (
$context->getImageObj() && $this->errors ) {
821 $response = implode(
"\n\n", $this->errors );
822 } elseif ( $this->errors ) {
823 $errorText = implode(
"\n\n", $this->errors );
824 $errorResponse = self::makeComment( $errorText );
825 if (
$context->shouldIncludeScripts() ) {
826 $errorResponse .=
'if (window.console && console.error) { console.error('
827 .
$context->encodeJson( $errorText )
840 DeferredUpdates::addCallableUpdate(
function () use ( $timing ) {
841 $measure = $timing->
measure(
'responseTime',
'requestStart',
'requestShutdown' );
842 if ( $measure !==
false ) {
843 $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
844 $stats->timing(
'resourceloader.responseTime', $measure[
'duration'] * 1000 );
863 \MediaWiki\HeaderCallback::warnIfHeadersSent();
864 $rlMaxage = $this->config->get(
'ResourceLoaderMaxage' );
869 if ( is_null(
$context->getVersion() )
873 $maxage = $rlMaxage[
'unversioned'][
'client'];
874 $smaxage = $rlMaxage[
'unversioned'][
'server'];
878 $maxage = $rlMaxage[
'versioned'][
'client'];
879 $smaxage = $rlMaxage[
'versioned'][
'server'];
884 header(
'Content-Type: text/plain; charset=utf-8' );
888 } elseif (
$context->getOnly() ===
'styles' ) {
889 header(
'Content-Type: text/css; charset=utf-8' );
890 header(
'Access-Control-Allow-Origin: *' );
892 header(
'Content-Type: text/javascript; charset=utf-8' );
896 header(
'ETag: ' . $etag );
899 header(
'Cache-Control: private, no-cache, must-revalidate' );
900 header(
'Pragma: no-cache' );
902 header(
"Cache-Control: public, max-age=$maxage, s-maxage=$smaxage" );
903 $exp = min( $maxage, $smaxage );
904 header(
'Expires: ' .
wfTimestamp( TS_RFC2822, $exp + time() ) );
906 foreach ( $extra as
$header ) {
924 $clientKeys =
$context->getRequest()->getHeader(
'If-None-Match', WebRequest::GETHEADER_LIST );
926 if ( $clientKeys !==
false && !
$context->getDebug() && in_array( $etag, $clientKeys ) ) {
938 HttpStatus::header( 304 );
959 $rlMaxage = $this->config->get(
'ResourceLoaderMaxage' );
963 $maxage = is_null(
$context->getVersion() )
964 ? $rlMaxage[
'unversioned'][
'server']
965 : $rlMaxage[
'versioned'][
'server'];
983 $warnings = ob_get_contents();
984 if ( strlen( $warnings ) ) {
1008 $encText = str_replace(
'*/',
'* /', $text );
1009 return "/*\n$encText\n*/\n";
1019 return self::makeComment( self::formatExceptionNoComment( $e ) );
1033 return MWExceptionHandler::getPublicLogMessage( $e );
1036 return MWExceptionHandler::getLogMessage( $e ) .
1038 MWExceptionHandler::getRedactedTraceAsString( $e );
1053 array
$modules, array $missing = []
1058 if (
$modules === [] && $missing === [] ) {
1068 $data = $image->getImageData(
$context );
1069 if ( $data ===
false ) {
1071 $this->errors[] =
'Image generation failed';
1076 foreach ( $missing as $name ) {
1077 $states[$name] =
'missing';
1080 $filter =
$context->getOnly() ===
'styles' ?
'minify-css' :
'minify-js';
1082 foreach (
$modules as $name => $module ) {
1085 $implementKey = $name .
'@' . $module->getVersionHash(
$context );
1088 if ( isset(
$content[
'headers'] ) ) {
1089 $this->extraHeaders = array_merge( $this->extraHeaders,
$content[
'headers'] );
1096 if ( is_string( $scripts ) ) {
1098 $strContent = $scripts;
1099 } elseif ( is_array( $scripts ) ) {
1101 $strContent = self::makeLoaderImplementScript(
1116 $strContent = isset( $styles[
'css'] ) ? implode(
'', $styles[
'css'] ) :
'';
1119 $scripts =
$content[
'scripts'] ??
'';
1120 if ( is_string( $scripts ) ) {
1121 if ( $name ===
'site' || $name ===
'user' ) {
1127 $scripts = self::filter(
'minify-js', $scripts );
1133 $strContent = self::makeLoaderImplementScript(
1145 $strContent = self::filter(
$filter, $strContent );
1152 if (
$context->getOnly() ===
'scripts' ) {
1156 $out .= $strContent;
1159 }
catch ( Exception $e ) {
1160 $this->
outputErrorAndLog( $e,
'Generating module package failed: {exception}' );
1163 $states[$name] =
'error';
1173 foreach (
$modules as $name => $module ) {
1174 $states[$name] =
'ready';
1180 $stateScript = self::makeLoaderStateScript(
$context, $states );
1182 $stateScript = self::filter(
'minify-js', $stateScript );
1187 } elseif ( $states ) {
1188 $this->errors[] =
'Problematic modules: '
1200 private function ensureNewline( $str ) {
1201 $end = substr( $str, -1 );
1202 if ( $end ===
false || $end ===
'' || $end ===
"\n" ) {
1217 $module = $this->
getModule( $moduleName );
1218 if ( in_array( $messageKey, $module->getMessages() ) ) {
1219 $moduleNames[] = $moduleName;
1222 return $moduleNames;
1247 if ( $scripts->value ===
'' ) {
1249 } elseif (
$context->getDebug() ) {
1250 $scripts =
new XmlJsCode(
"function ( $, jQuery, require, module ) {\n{$scripts->value}\n}" );
1252 $scripts =
new XmlJsCode(
'function($,jQuery,require,module){' . $scripts->value .
'}' );
1254 } elseif ( is_array( $scripts ) && isset( $scripts[
'files'] ) ) {
1255 $files = $scripts[
'files'];
1259 if (
$file[
'type'] ===
'script' ) {
1262 $file =
new XmlJsCode(
"function ( require, module ) {\n{$file['content']}\n}" );
1271 'main' => $scripts[
'main'],
1274 } elseif ( !is_string( $scripts ) && !is_array( $scripts ) ) {
1275 throw new MWException(
'Invalid scripts error. Array of URLs or string of code expected.' );
1288 self::trimArray( $module );
1300 return 'mw.messages.set('
1301 . self::encodeJsonForScript( (
object)$messages )
1314 foreach ( $stylePairs as $media => $styles ) {
1318 $styles = (array)$styles;
1319 foreach ( $styles as $style ) {
1320 $style = trim( $style );
1322 if ( $style !==
'' ) {
1327 if ( $media ===
'' || $media ==
'all' ) {
1329 } elseif ( is_string( $media ) ) {
1330 $out[] =
"@media $media {\n" . str_replace(
"\n",
"\n\t",
"\t" . $style ) .
"}";
1358 $jsonFlags = JSON_UNESCAPED_SLASHES |
1359 JSON_UNESCAPED_UNICODE |
1362 if ( self::inDebugMode() ) {
1363 $jsonFlags |= JSON_PRETTY_PRINT;
1365 return json_encode( $data, $jsonFlags );
1383 return 'mw.loader.state('
1388 private static function isEmptyObject( stdClass $obj ) {
1389 foreach ( $obj as $key => $value ) {
1407 private static function trimArray( array &$array ) {
1408 $i = count( $array );
1410 if ( $array[$i] ===
null
1411 || $array[$i] === []
1412 || ( $array[$i] instanceof
XmlJsCode && $array[$i]->value ===
'{}' )
1413 || ( $array[$i] instanceof stdClass && self::isEmptyObject( $array[$i] ) )
1415 unset( $array[$i] );
1454 foreach (
$modules as $i => &$module ) {
1456 $index[$module[0]] = $i;
1459 if ( isset( $module[2] ) ) {
1460 foreach ( $module[2] as &$dependency ) {
1461 if ( isset( $index[$dependency] ) ) {
1463 $dependency = $index[$dependency];
1469 array_walk(
$modules, [ self::class,
'trimArray' ] );
1471 return 'mw.loader.register('
1493 return 'mw.loader.addSource('
1506 return '(RLQ=window.RLQ||[]).push(function(){' .
1507 trim( $script ) .
'});';
1520 return '(RLQ=window.RLQ||[]).push(['
1521 . self::encodeJsonForScript(
$modules ) .
','
1522 .
'function(){' . trim( $script ) .
'}'
1538 $js = self::makeLoaderConditionalScript( $script );
1540 if ( $nonce ===
null ) {
1541 wfWarn( __METHOD__ .
" did not get nonce. Will break CSP" );
1542 } elseif ( $nonce !==
false ) {
1546 $escNonce =
' nonce="' . htmlspecialchars( $nonce ) .
'"';
1549 return new WrappedString(
1550 Html::inlineScript( $js, $nonce ),
1551 "<script$escNonce>(RLQ=window.RLQ||[]).push(function(){",
1565 $json = self::encodeJsonForScript( $configuration );
1566 if ( $json ===
false ) {
1568 'JSON serialization of config data failed. ' .
1569 'This usually means the config data is not valid UTF-8.'
1572 return 'mw.log.error(' . self::encodeJsonForScript( $e->__toString() ) .
');';
1574 return "mw.config.set($json);";
1593 $pos = strrpos( $module,
'.' );
1594 $prefix = $pos ===
false ?
'' : substr( $module, 0, $pos );
1595 $suffix = $pos ===
false ? $module : substr( $module, $pos + 1 );
1596 $moduleMap[$prefix][] = $suffix;
1600 foreach ( $moduleMap as $prefix => $suffixes ) {
1601 $p = $prefix ===
'' ?
'' : $prefix .
'.';
1602 $arr[] = $p . implode(
',', $suffixes );
1604 return implode(
'|', $arr );
1620 $exploded = explode(
'|',
$modules );
1621 foreach ( $exploded as $group ) {
1622 if ( strpos( $group,
',' ) ===
false ) {
1628 $pos = strrpos( $group,
'.' );
1629 if ( $pos ===
false ) {
1631 $retval = array_merge( $retval, explode(
',', $group ) );
1634 $prefix = substr( $group, 0, $pos );
1635 $suffixes = explode(
',', substr( $group, $pos + 1 ) );
1636 foreach ( $suffixes as $suffix ) {
1637 $retval[] =
"$prefix.$suffix";
1651 if ( self::$debugMode ===
null ) {
1653 self::$debugMode =
$wgRequest->getFuzzyBool(
'debug',
1657 return self::$debugMode;
1671 self::$debugMode =
null;
1686 $query = self::createLoaderQuery(
$context, $extraQuery );
1702 return self::makeLoaderQuery(
1710 $context->getRequest()->getBool(
'printable' ),
1711 $context->getRequest()->getBool(
'handheld' ),
1733 $version =
null,
$debug =
false, $only =
null, $printable =
false,
1734 $handheld =
false, $extraQuery = []
1737 'modules' => self::makePackedModulesString(
$modules ),
1743 if (
$lang !== ResourceLoaderContext::DEFAULT_LANG ) {
1744 $query[
'lang'] =
$lang;
1746 if ( $skin !== ResourceLoaderContext::DEFAULT_SKIN ) {
1747 $query[
'skin'] = $skin;
1750 $query[
'debug'] =
'true';
1752 if ( $user !==
null ) {
1753 $query[
'user'] = $user;
1755 if ( $version !==
null ) {
1756 $query[
'version'] = $version;
1758 if ( $only !==
null ) {
1759 $query[
'only'] = $only;
1762 $query[
'printable'] = 1;
1765 $query[
'handheld'] = 1;
1767 $query += $extraQuery;
1784 return strcspn( $moduleName,
'!,|', 0, 255 ) === strlen( $moduleName );
1802 if ( !class_exists(
'Less_Parser' ) ) {
1803 throw new MWException(
'MediaWiki requires the less.php parser' );
1806 $parser =
new Less_Parser;
1807 $parser->ModifyVars( $vars );
1808 $parser->SetImportDirs( [
1809 "$IP/resources/src/mediawiki.less/" =>
'',
1811 $parser->SetOption(
'relativeUrls',
false );
$wgResourceLoaderDebug
The default debug mode (on/off) for of ResourceLoader requests.
$wgShowExceptionDetails
If set to true, uncaught exceptions will print the exception message and a complete stack trace to ou...
wfWarn( $msg, $callerOffset=1, $level=E_USER_NOTICE)
Send a warning either to the debug log or in a PHP error depending on $wgDevelopmentWarnings.
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
wfAppendQuery( $url, $query)
Append a query string to an existing URL, which may or may not already have query string parameters a...
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
wfResetOutputBuffers( $resetGzipEncoding=true)
Clear away any user-level output buffers, discarding contents.
if(! $wgDBerrorLogTZ) $wgRequest
isCacheGood( $timestamp='')
Check if up to date cache file exists.
fetchText()
Get the uncompressed text from the cache.
cacheTimestamp()
Get the last-modified timestamp of the cache file.
static minify( $s)
Returns minified JavaScript code.
static logException( $e, $catcher=self::CAUGHT_BY_OTHER, $extraData=[])
Log an exception to the exception log (if enabled).
This class generates message blobs for use by ResourceLoader.
static transformCssMedia( $media)
Transform "media" attribute based on request parameters.
ResourceLoader request result caching in the file system.
static useFileCache(ResourceLoaderContext $context)
Check if an RL request can be cached.
static newFromContext(ResourceLoaderContext $context)
Construct an ResourceFileCache from a context.
Context object that contains information about the state of a specific ResourceLoader web request.
An object to represent a path to a JavaScript/CSS file, along with a remote and local base path,...
Abstraction for ResourceLoader modules, with name registration and maxage functionality.
static expandRelativePaths(array $filePaths)
Expand directories relative to $IP.
static getVary(ResourceLoaderContext $context)
Get vary string.
ResourceLoader is a loading system for JavaScript and CSS resources.
static makeLoaderSourcesScript(ResourceLoaderContext $context, array $sources)
Returns JS code which calls mw.loader.addSource() with the given parameters.
static makeInlineScript( $script, $nonce=null)
Returns an HTML script tag that runs given JS code after startup and base modules.
static expandModuleNames( $modules)
Expand a string of the form jquery.foo,bar|jquery.ui.baz,quux to an array of module names like ‘[ 'jq...
__construct(Config $config=null, LoggerInterface $logger=null)
Register core modules and runs registration hooks.
static formatExceptionNoComment( $e)
Handle exception display.
makeVersionQuery(ResourceLoaderContext $context, array $modules=null)
Get the expected value of the 'version' query parameter.
tryRespondFromFileCache(ResourceFileCache $fileCache, ResourceLoaderContext $context, $etag)
Send out code for a response from file cache if possible.
isFileModule( $name)
Whether the module is a ResourceLoaderFileModule (including subclasses).
getModuleNames()
Get a list of module names.
static makeLoaderConditionalScript( $script)
Wraps JavaScript code to run after the startup module.
static trimArray(array &$array)
Remove empty values from the end of an array.
setMessageBlobStore(MessageBlobStore $blobStore)
static inDebugMode()
Determine whether debug mode was requested Order of priority is 1) request param, 2) cookie,...
static makeConfigSetScript(array $configuration)
Returns JS code which will set the MediaWiki configuration array to the given value.
static makeCombinedStyles(array $stylePairs)
Combines an associative array mapping media type to CSS into a single stylesheet with "@media" blocks...
makeModuleResponse(ResourceLoaderContext $context, array $modules, array $missing=[])
Generate code for a response.
setLogger(LoggerInterface $logger)
getLoadScript( $source)
Get the URL to the load.php endpoint for the given ResourceLoader source.
static makeLoaderRegisterScript(ResourceLoaderContext $context, array $modules)
Returns JS code which calls mw.loader.register with the given parameter.
static createLoaderQuery(ResourceLoaderContext $context, $extraQuery=[])
Helper for createLoaderURL()
sendResponseHeaders(ResourceLoaderContext $context, $etag, $errors, array $extra=[])
Send main response headers to the client.
getLessVars()
Get global LESS variables.
static makeMessageSetScript( $messages)
Returns JS code which, when called, will register a given list of messages.
array[] $moduleInfos
Map of (module name => associative info array)
tryRespondNotModified(ResourceLoaderContext $context, $etag)
Respond with HTTP 304 Not Modified if appropiate.
static makeLoaderQuery( $modules, $lang, $skin, $user=null, $version=null, $debug=false, $only=null, $printable=false, $handheld=false, $extraQuery=[])
Build a query array (array representation of query string) for load.php.
getSources()
Get the list of sources.
addSource( $id, $loadUrl=null)
Add a foreign source of modules.
static makeInlineCodeWithModule( $modules, $script)
Wraps JavaScript code to run after a required module.
static clearCache()
Reset static members used for caching.
ensureNewline( $str)
Ensure the string is either empty or ends in a line break.
string[] $extraHeaders
Extra HTTP response headers from modules loaded in makeModuleResponse()
outputErrorAndLog(Exception $e, $msg, array $context=[])
Add an error to the 'errors' array and log it.
array $testModuleNames
Associative array mapping framework ids to a list of names of test suite modules like [ 'qunit' => [ ...
static makePackedModulesString( $modules)
Convert an array of module names to a packed query string.
getTestSuiteModuleNames()
Get a list of module names with QUnit test suites.
string[] $testSuiteModuleNames
List of module names that contain QUnit test suites.
getModule( $name)
Get the ResourceLoaderModule object for a given module name.
array $sources
Map of (source => path); E.g.
isModuleRegistered( $name)
Check whether a ResourceLoader module is registered.
static applyFilter( $filter, $data)
createLoaderURL( $source, ResourceLoaderContext $context, $extraQuery=[])
Build a load.php URL.
static makeLoaderImplementScript(ResourceLoaderContext $context, $name, $scripts, $styles, $messages, $templates)
Return JS code that calls mw.loader.implement with given module properties.
measureResponseTime(Timing $timing)
static formatException( $e)
Handle exception display.
getModulesByMessage( $messageKey)
Get names of modules that use a certain message.
static encodeJsonForScript( $data)
Wrapper around json_encode that avoids needless escapes, and pretty-prints in debug mode.
MessageBlobStore $blobStore
array $errors
Errors accumulated during current respond() call.
static makeComment( $text)
Generate a CSS or JS comment block.
getLessCompiler( $vars=[])
Returns LESS compiler set up for use with MediaWiki.
getCombinedVersion(ResourceLoaderContext $context, array $moduleNames)
Helper method to get and combine versions of multiple modules.
respond(ResourceLoaderContext $context)
Output a response to a load request, including the content-type header.
static makeHash( $value)
Create a hash for module versioning purposes.
static isValidModuleName( $moduleName)
Check a module name for validity.
static makeLoaderStateScript(ResourceLoaderContext $context, array $states)
Returns a JS call to mw.loader.state, which sets the state of modules to a given value:
static filter( $filter, $data, array $options=[])
Run JavaScript or CSS data through a filter, caching the filtered result for future calls.
preloadModuleInfo(array $moduleNames, ResourceLoaderContext $context)
Load information stored in the database about modules.
An interface to help developers measure the performance of their applications.
measure( $measureName, $startMark='requestStart', $endMark=null)
This method stores the duration between two marks along with the associated name (a "measure").
A wrapper class which causes Xml::encodeJsVar() and Xml::encodeJsCall() to interpret a given string a...
static encodeObject( $obj, $pretty=false)
Encode an object containing XmlJsCode objects.
static encodeJsCall( $name, $args, $pretty=false)
Create a call to a JavaScript function.
Interface for configuration instances.
get( $name)
Get a configuration variable such as "Sitename" or "UploadMaintenance.".
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
if(!isset( $args[0])) $lang