summaryrefslogtreecommitdiff
path: root/includes/resourceloader/ResourceLoaderStartUpModule.php
diff options
context:
space:
mode:
Diffstat (limited to 'includes/resourceloader/ResourceLoaderStartUpModule.php')
-rw-r--r--includes/resourceloader/ResourceLoaderStartUpModule.php191
1 files changed, 84 insertions, 107 deletions
diff --git a/includes/resourceloader/ResourceLoaderStartUpModule.php b/includes/resourceloader/ResourceLoaderStartUpModule.php
index b2fbae9c..87d8ee20 100644
--- a/includes/resourceloader/ResourceLoaderStartUpModule.php
+++ b/includes/resourceloader/ResourceLoaderStartUpModule.php
@@ -24,14 +24,10 @@
class ResourceLoaderStartUpModule extends ResourceLoaderModule {
- /* Protected Members */
-
- protected $modifiedTime = array();
+ // Cache for getConfigSettings() as it's called by multiple methods
protected $configVars = array();
protected $targets = array( 'desktop', 'mobile' );
- /* Protected Methods */
-
/**
* @param ResourceLoaderContext $context
* @return array
@@ -92,6 +88,7 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
'wgContentNamespaces' => MWNamespace::getContentNamespaces(),
'wgSiteName' => $conf->get( 'Sitename' ),
'wgDBname' => $conf->get( 'DBname' ),
+ 'wgExtraSignatureNamespaces' => $conf->get( 'ExtraSignatureNamespaces' ),
'wgAvailableSkins' => Skin::getSkinNames(),
'wgExtensionAssetsPath' => $conf->get( 'ExtensionAssetsPath' ),
// MediaWiki sets cookies to have this prefix by default
@@ -104,6 +101,9 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
'wgLegalTitleChars' => Title::convertByteClassToUnicodeClass( Title::legalChars() ),
'wgResourceLoaderStorageVersion' => $conf->get( 'ResourceLoaderStorageVersion' ),
'wgResourceLoaderStorageEnabled' => $conf->get( 'ResourceLoaderStorageEnabled' ),
+ 'wgResourceLoaderLegacyModules' => self::getLegacyModules(),
+ 'wgForeignUploadTargets' => $conf->get( 'ForeignUploadTargets' ),
+ 'wgEnableUploads' => $conf->get( 'EnableUploads' ),
);
Hooks::run( 'ResourceLoaderGetConfigVars', array( &$vars ) );
@@ -159,7 +159,7 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
* data send to the client.
*
* @param array &$registryData Modules keyed by name with properties:
- * - number 'version'
+ * - string 'version'
* - array 'dependencies'
* - string|null 'group'
* - string 'source'
@@ -191,6 +191,9 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
$resourceLoader = $context->getResourceLoader();
$target = $context->getRequest()->getVal( 'target', 'desktop' );
+ // Bypass target filter if this request is from a unit test context. To prevent misuse in
+ // production, this is only allowed if testing is enabled server-side.
+ $byPassTargetFilter = $this->getConfig()->get( 'EnableJavaScriptTest' ) && $target === 'test';
$out = '';
$registryData = array();
@@ -199,7 +202,7 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
foreach ( $resourceLoader->getModuleNames() as $name ) {
$module = $resourceLoader->getModule( $name );
$moduleTargets = $module->getTargets();
- if ( !in_array( $target, $moduleTargets ) ) {
+ if ( !$byPassTargetFilter && !in_array( $target, $moduleTargets ) ) {
continue;
}
@@ -210,31 +213,27 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
continue;
}
- // Coerce module timestamp to UNIX timestamp.
- // getModifiedTime() is supposed to return a UNIX timestamp, but custom implementations
- // might forget. TODO: Maybe emit warning?
- $moduleMtime = wfTimestamp( TS_UNIX, $module->getModifiedTime( $context ) );
+ $versionHash = $module->getVersionHash( $context );
+ if ( strlen( $versionHash ) !== 8 ) {
+ // Module implementation either broken or deviated from ResourceLoader::makeHash
+ // Asserted by tests/phpunit/structure/ResourcesTest.
+ $versionHash = ResourceLoader::makeHash( $versionHash );
+ }
$skipFunction = $module->getSkipFunction();
if ( $skipFunction !== null && !ResourceLoader::inDebugMode() ) {
$skipFunction = $resourceLoader->filter( 'minify-js',
$skipFunction,
- // There will potentially be lots of these little string in the registrations
+ // There will potentially be lots of these little strings in the registrations
// manifest, we don't want to blow up the startup module with
- // "/* cache key: ... */" all over it in non-debug mode.
+ // "/* cache key: ... */" all over it.
/* cacheReport = */ false
);
}
- $mtime = max(
- $moduleMtime,
- wfTimestamp( TS_UNIX, $this->getConfig()->get( 'CacheEpoch' ) )
- );
-
$registryData[$name] = array(
- // Convert to numbers as wfTimestamp always returns a string, even for TS_UNIX
- 'version' => (int) $mtime,
- 'dependencies' => $module->getDependencies(),
+ 'version' => $versionHash,
+ 'dependencies' => $module->getDependencies( $context ),
'group' => $module->getGroup(),
'source' => $module->getSource(),
'loader' => $module->getLoaderScript(),
@@ -263,7 +262,7 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
continue;
}
- // Call mw.loader.register(name, timestamp, dependencies, group, source, skip)
+ // Call mw.loader.register(name, version, dependencies, group, source, skip)
$registrations[] = array(
$name,
$data['version'],
@@ -276,13 +275,11 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
}
// Register modules
- $out .= ResourceLoader::makeLoaderRegisterScript( $registrations );
+ $out .= "\n" . ResourceLoader::makeLoaderRegisterScript( $registrations );
return $out;
}
- /* Methods */
-
/**
* @return bool
*/
@@ -299,6 +296,20 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
return array( 'jquery', 'mediawiki' );
}
+ public static function getLegacyModules() {
+ global $wgIncludeLegacyJavaScript, $wgPreloadJavaScriptMwUtil;
+
+ $legacyModules = array();
+ if ( $wgIncludeLegacyJavaScript ) {
+ $legacyModules[] = 'mediawiki.legacy.wikibits';
+ }
+ if ( $wgPreloadJavaScriptMwUtil ) {
+ $legacyModules[] = 'mediawiki.util';
+ }
+
+ return $legacyModules;
+ }
+
/**
* Get the load URL of the startup modules.
*
@@ -309,24 +320,16 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
* @return string
*/
public static function getStartupModulesUrl( ResourceLoaderContext $context ) {
+ $rl = $context->getResourceLoader();
$moduleNames = self::getStartupModules();
- // Get the latest version
- $loader = $context->getResourceLoader();
- $version = 1;
- foreach ( $moduleNames as $moduleName ) {
- $version = max( $version,
- $loader->getModule( $moduleName )->getModifiedTime( $context )
- );
- }
-
$query = array(
'modules' => ResourceLoader::makePackedModulesString( $moduleNames ),
'only' => 'scripts',
'lang' => $context->getLanguage(),
'skin' => $context->getSkin(),
'debug' => $context->getDebug() ? 'true' : 'false',
- 'version' => wfTimestamp( TS_ISO_8601_BASIC, $version )
+ 'version' => $rl->getCombinedVersion( $context, $moduleNames ),
);
// Ensure uniform query order
ksort( $query );
@@ -339,40 +342,25 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
*/
public function getScript( ResourceLoaderContext $context ) {
global $IP;
+ if ( $context->getOnly() !== 'scripts' ) {
+ return '/* Requires only=script */';
+ }
$out = file_get_contents( "$IP/resources/src/startup.js" );
- if ( $context->getOnly() === 'scripts' ) {
- // Startup function
- $configuration = $this->getConfigSettings( $context );
- $registrations = $this->getModuleRegistrations( $context );
+ $pairs = array_map( function ( $value ) {
+ $value = FormatJson::encode( $value, ResourceLoader::inDebugMode(), FormatJson::ALL_OK );
// Fix indentation
- $registrations = str_replace( "\n", "\n\t", trim( $registrations ) );
- $mwMapJsCall = Xml::encodeJsCall(
- 'mw.Map',
- array( $this->getConfig()->get( 'LegacyJavaScriptGlobals' ) )
- );
- $mwConfigSetJsCall = Xml::encodeJsCall(
- 'mw.config.set',
- array( $configuration ),
- ResourceLoader::inDebugMode()
- );
-
- $out .= "var startUp = function () {\n" .
- "\tmw.config = new " .
- $mwMapJsCall . "\n" .
- "\t$registrations\n" .
- "\t" . $mwConfigSetJsCall .
- "};\n";
-
- // Conditional script injection
- $scriptTag = Html::linkedScript( self::getStartupModulesUrl( $context ) );
- $out .= "if ( isCompatible() ) {\n" .
- "\t" . Xml::encodeJsCall( 'document.write', array( $scriptTag ) ) .
- "\n}";
- }
-
- return $out;
+ $value = str_replace( "\n", "\n\t", $value );
+ return $value;
+ }, array(
+ '$VARS.wgLegacyJavaScriptGlobals' => $this->getConfig()->get( 'LegacyJavaScriptGlobals' ),
+ '$VARS.configuration' => $this->getConfigSettings( $context ),
+ '$VARS.baseModulesUri' => self::getStartupModulesUrl( $context ),
+ ) );
+ $pairs['$CODE.registrations()'] = str_replace( "\n", "\n\t", trim( $this->getModuleRegistrations( $context ) ) );
+
+ return strtr( $out, $pairs );
}
/**
@@ -383,59 +371,48 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
}
/**
+ * Get the definition summary for this module.
+ *
* @param ResourceLoaderContext $context
- * @return array|mixed
+ * @return array
*/
- public function getModifiedTime( ResourceLoaderContext $context ) {
+ public function getDefinitionSummary( ResourceLoaderContext $context ) {
global $IP;
+ $summary = parent::getDefinitionSummary( $context );
+ $summary[] = array(
+ // Detect changes to variables exposed in mw.config (T30899).
+ 'vars' => $this->getConfigSettings( $context ),
+ // Changes how getScript() creates mw.Map for mw.config
+ 'wgLegacyJavaScriptGlobals' => $this->getConfig()->get( 'LegacyJavaScriptGlobals' ),
+ // Detect changes to the module registrations
+ 'moduleHashes' => $this->getAllModuleHashes( $context ),
- $hash = $context->getHash();
- if ( isset( $this->modifiedTime[$hash] ) ) {
- return $this->modifiedTime[$hash];
- }
-
- // Call preloadModuleInfo() on ALL modules as we're about
- // to call getModifiedTime() on all of them
- $loader = $context->getResourceLoader();
- $loader->preloadModuleInfo( $loader->getModuleNames(), $context );
-
- $time = max(
- wfTimestamp( TS_UNIX, $this->getConfig()->get( 'CacheEpoch' ) ),
- filemtime( "$IP/resources/src/startup.js" ),
- $this->getHashMtime( $context )
+ 'fileMtimes' => array(
+ filemtime( "$IP/resources/src/startup.js" ),
+ ),
);
-
- // ATTENTION!: Because of the line below, this is not going to cause
- // infinite recursion - think carefully before making changes to this
- // code!
- // Pre-populate modifiedTime with something because the loop over
- // all modules below includes the startup module (this module).
- $this->modifiedTime[$hash] = 1;
-
- foreach ( $loader->getModuleNames() as $name ) {
- $module = $loader->getModule( $name );
- $time = max( $time, $module->getModifiedTime( $context ) );
- }
-
- $this->modifiedTime[$hash] = $time;
- return $this->modifiedTime[$hash];
+ return $summary;
}
/**
- * Hash of all dynamic data embedded in getScript().
- *
- * Detect changes to mw.config settings embedded in #getScript (bug 28899).
+ * Helper method for getDefinitionSummary().
*
* @param ResourceLoaderContext $context
- * @return string Hash
+ * @return string SHA-1
*/
- public function getModifiedHash( ResourceLoaderContext $context ) {
- $data = array(
- 'vars' => $this->getConfigSettings( $context ),
- 'wgLegacyJavaScriptGlobals' => $this->getConfig()->get( 'LegacyJavaScriptGlobals' ),
- );
-
- return md5( serialize( $data ) );
+ protected function getAllModuleHashes( ResourceLoaderContext $context ) {
+ $rl = $context->getResourceLoader();
+ // Preload for getCombinedVersion()
+ $rl->preloadModuleInfo( $rl->getModuleNames(), $context );
+
+ // ATTENTION: Because of the line below, this is not going to cause infinite recursion.
+ // Think carefully before making changes to this code!
+ // Pre-populate versionHash with something because the loop over all modules below includes
+ // the startup module (this module).
+ // See ResourceLoaderModule::getVersionHash() for usage of this cache.
+ $this->versionHash[$context->getHash()] = null;
+
+ return $rl->getCombinedVersion( $context, $rl->getModuleNames() );
}
/**