http://www.mediawiki.org/wiki/Special:Code/MediaWiki/73673
Revision: 73673
Author: tparscal
Date: 2010-09-24 18:49:19 +0000 (Fri, 24 Sep 2010)
Log Message:
-----------
* Moved registration generation to startup module.
* Moved some javascript code generation to reusable functions (more to do).
* Reduced the code output by using mutliple calling method for
mediaWiki.loader.state.
* Moved CSS minification to the end (should be a bit faster than running it for
each module).
Modified Paths:
--------------
trunk/phase3/includes/ResourceLoader.php
trunk/phase3/includes/ResourceLoaderContext.php
trunk/phase3/includes/ResourceLoaderModule.php
trunk/phase3/resources/mediawiki/mediawiki.js
Modified: trunk/phase3/includes/ResourceLoader.php
===================================================================
--- trunk/phase3/includes/ResourceLoader.php 2010-09-24 18:48:20 UTC (rev
73672)
+++ trunk/phase3/includes/ResourceLoader.php 2010-09-24 18:49:19 UTC (rev
73673)
@@ -53,7 +53,16 @@
}
}
- protected static function preloadModuleInfo( $modules,
ResourceLoaderContext $context ) {
+ /*
+ * Loads information stored in the database about modules
+ *
+ * This is not inside the module code because it's so much more
performant to request all of the information at once
+ * than it is to have each module requests it's own information.
+ *
+ * @param $modules array list of modules to preload information for
+ * @param $context ResourceLoaderContext context to load the
information within
+ */
+ protected static function preloadModuleInfo( array $modules,
ResourceLoaderContext $context ) {
$dbr = wfGetDb( DB_SLAVE );
$skin = $context->getSkin();
$lang = $context->getLanguage();
@@ -107,8 +116,7 @@
*
* @param $filter String: name of filter to run
* @param $data String: text to filter, such as JavaScript or CSS text
- * @param $file String: path to file being filtered, (optional: only
required
- * for CSS to resolve paths)
+ * @param $file String: path to file being filtered, (optional: only
required for CSS to resolve paths)
* @return String: filtered data
*/
protected static function filter( $filter, $data ) {
@@ -227,54 +235,6 @@
}
/**
- * Gets registration code for all modules
- *
- * @param $context ResourceLoaderContext object
- * @return String: JavaScript code for registering all modules with the
client loader
- */
- public static function getModuleRegistrations( ResourceLoaderContext
$context ) {
- wfProfileIn( __METHOD__ );
- self::initialize();
-
- $scripts = '';
- $registrations = array();
-
- foreach ( self::$modules as $name => $module ) {
- // Support module loader scripts
- if ( ( $loader = $module->getLoaderScript() ) !== false
) {
- $deps = FormatJson::encode(
$module->getDependencies() );
- $group = FormatJson::encode(
$module->getGroup() );
- $version = wfTimestamp( TS_ISO_8601, round(
$module->getModifiedTime( $context ), -2 ) );
- $scripts .= "( function( name, version,
dependencies ) { $loader } )\n" .
- "( '$name', '$version', $deps, $group
);\n";
- }
- // Automatically register module
- else {
- // Modules without dependencies or a group pass
two arguments (name, timestamp) to
- // mediaWiki.loader.register()
- if ( !count( $module->getDependencies() &&
$module->getGroup() === null ) ) {
- $registrations[] = array( $name,
$module->getModifiedTime( $context ) );
- }
- // Modules with dependencies but no group pass
three arguments (name, timestamp, dependencies)
- // to mediaWiki.loader.register()
- else if ( $module->getGroup() === null ) {
- $registrations[] = array(
- $name,
$module->getModifiedTime( $context ), $module->getDependencies() );
- }
- // Modules with dependencies pass four
arguments (name, timestamp, dependencies, group)
- // to mediaWiki.loader.register()
- else {
- $registrations[] = array(
- $name,
$module->getModifiedTime( $context ), $module->getDependencies(),
$module->getGroup() );
- }
- }
- }
- $out = $scripts . "mediaWiki.loader.register( " .
FormatJson::encode( $registrations ) . " );\n";
- wfProfileOut( __METHOD__ );
- return $out;
- }
-
- /**
* Get the highest modification time of all modules, based on a given
* combination of language code, skin name and debug mode flag.
*
@@ -356,99 +316,125 @@
return;
}
- // Use output buffering
- ob_start();
-
// Pre-fetch blobs
$blobs = $context->shouldIncludeMessages() ?
MessageBlobStore::get( $modules,
$context->getLanguage() ) : array();
// Generate output
+ $out = '';
foreach ( $modules as $name ) {
wfProfileIn( __METHOD__ . '-' . $name );
+
// Scripts
$scripts = '';
-
if ( $context->shouldIncludeScripts() ) {
$scripts .= self::$modules[$name]->getScript(
$context ) . "\n";
}
// Styles
$styles = array();
-
if (
- $context->shouldIncludeStyles()
- && ( count( $styles =
self::$modules[$name]->getStyles( $context ) ) )
+ $context->shouldIncludeStyles() &&
+ ( count( $styles =
self::$modules[$name]->getStyles( $context ) ) )
) {
- foreach ( $styles as $media => $style ) {
- if ( self::$modules[$name]->getFlip(
$context ) ) {
+ // Flip CSS on a per-module basis
+ if ( self::$modules[$name]->getFlip( $context )
) {
+ foreach ( $styles as $media => $style )
{
$styles[$media] = self::filter(
'flip-css', $style );
}
- if ( !$context->getDebug() ) {
- $styles[$media] = self::filter(
'minify-css', $style );
- }
}
}
// Messages
$messages = isset( $blobs[$name] ) ? $blobs[$name] :
'{}';
- // Output
- if ( $context->getOnly() === 'styles' ) {
- if ( $context->getDebug() ) {
- echo "/* $name */\n";
- foreach ( $styles as $media => $style )
{
- echo "@media $media {\n" .
str_replace( "\n", "\n\t", "\t" . $style ) . "\n}\n";
- }
- } else {
- foreach ( $styles as $media => $style )
{
- if ( strlen( $style ) ) {
- echo "@media $media{" .
$style . "}";
+ // Append output
+ switch ( $context->getOnly() ) {
+ case 'scripts':
+ $out .= $scripts;
+ break;
+ case 'styles':
+ $out .= self::makeCombinedStyles(
$styles );
+ break;
+ case 'messages':
+ $out .= self::makeMessageSetScript(
$messages );
+ break;
+ default:
+ // Minify CSS, unless in debug mode,
before embedding in implment script
+ if ( !$context->getDebug() ) {
+ foreach ( $styles as $media =>
$style ) {
+ $styles[$media] =
self::filter( 'minify-css', $style );
}
}
- }
- } else if ( $context->getOnly() === 'scripts' ) {
- echo $scripts;
- } else if ( $context->getOnly() === 'messages' ) {
- echo "mediaWiki.msg.set( $messages );\n";
- } else {
- if ( count( $styles ) ) {
- $styles = FormatJson::encode( $styles );
- } else {
- $styles = 'null';
- }
- echo "mediaWiki.loader.implement( '$name',
function() {{$scripts}},\n$styles,\n$messages );\n";
+ $out .=
self::makeLoaderImplementScript( $name, $scripts, $styles, $messages );
+ break;
}
+
wfProfileOut( __METHOD__ . '-' . $name );
}
- // Update the status of script-only modules
- if ( $context->getOnly() === 'scripts' && !in_array( 'startup',
$modules ) ) {
- $statuses = array();
-
- foreach ( $modules as $name ) {
- $statuses[$name] = 'ready';
- }
-
- $statuses = FormatJson::encode( $statuses );
- echo "mediaWiki.loader.state( $statuses );\n";
- }
-
- // Register missing modules
+ // Update module states
if ( $context->shouldIncludeScripts() ) {
- foreach ( $missing as $name ) {
- echo "mediaWiki.loader.register( '$name', null,
'missing' );\n";
+ // Set the state of modules loaded as only scripts to
ready
+ if ( count( $modules ) && $context->getOnly() ===
'scripts' && !in_array( 'startup', $modules ) ) {
+ $out .= self::makeLoaderStateScript(
array_fill_keys( $modules, 'ready' ) );
}
+ // Set the state of modules which were requested but
unavailable as missing
+ if ( count( $missing ) ) {
+ $out .= self::makeLoaderStateScript(
array_fill_keys( $missing, 'missing' ) );
+ }
}
- // Output the appropriate header
- if ( $context->getOnly() !== 'styles' ) {
- if ( $context->getDebug() ) {
- ob_end_flush();
+ // Send output
+ if ( $context->getDebug() ) {
+ echo $out;
+ } else {
+ if ( $context->getOnly() === 'styles' ) {
+ echo self::filter( 'minify-css', $out );
} else {
- echo self::filter( 'minify-js', ob_get_clean()
);
+ echo self::filter( 'minify-js', $out );
}
}
+
wfProfileOut( __METHOD__ );
}
+
+ public static function makeLoaderImplementScript( $name, $scripts,
$styles, $messages ) {
+ if ( is_array( $scripts ) ) {
+ $scripts = implode( $scripts, "\n" );
+ }
+ if ( is_array( $styles ) ) {
+ $styles = count( $styles ) ? FormatJson::encode(
$styles ) : 'null';
+ }
+ if ( is_array( $messages ) ) {
+ $messages = count( $messages ) ? FormatJson::encode(
$messages ) : 'null';
+ }
+ return "mediaWiki.loader.implement( '$name', function()
{{$scripts}},\n$styles,\n$messages );\n";
+ }
+
+ public static function makeMessageSetScript( $messages ) {
+ if ( is_array( $messages ) ) {
+ $messages = count( $messages ) ? FormatJson::encode(
$messages ) : 'null';
+ }
+ return "mediaWiki.msg.set( $messages );\n";
+ }
+
+ public static function makeCombinedStyles( array $styles ) {
+ $out = '';
+ foreach ( $styles as $media => $style ) {
+ $out .= "@media $media {\n" . str_replace( "\n",
"\n\t", "\t" . $style ) . "\n}\n";
+ }
+ return $out;
+ }
+
+ public static function makeLoaderStateScript( $name, $state = null ) {
+ if ( is_array( $name ) ) {
+ $statuses = FormatJson::encode( $name );
+ return "mediaWiki.loader.state( $statuses );\n";
+ } else {
+ $name = Xml::escapeJsString( $name );
+ $name = Xml::escapeJsString( $state );
+ return "mediaWiki.loader.state( '$name', '$state' );\n";
+ }
+ }
}
Modified: trunk/phase3/includes/ResourceLoaderContext.php
===================================================================
--- trunk/phase3/includes/ResourceLoaderContext.php 2010-09-24 18:48:20 UTC
(rev 73672)
+++ trunk/phase3/includes/ResourceLoaderContext.php 2010-09-24 18:49:19 UTC
(rev 73673)
@@ -27,6 +27,7 @@
* of a specific loader request
*/
class ResourceLoaderContext {
+
/* Protected Members */
protected $request;
Modified: trunk/phase3/includes/ResourceLoaderModule.php
===================================================================
--- trunk/phase3/includes/ResourceLoaderModule.php 2010-09-24 18:48:20 UTC
(rev 73672)
+++ trunk/phase3/includes/ResourceLoaderModule.php 2010-09-24 18:49:19 UTC
(rev 73673)
@@ -26,6 +26,7 @@
* Abstraction for resource loader modules, with name registration and maxage
functionality.
*/
abstract class ResourceLoaderModule {
+
/* Protected Members */
protected $name = null;
@@ -1038,25 +1039,66 @@
return $vars;
}
+ /**
+ * Gets registration code for all modules
+ *
+ * @param $context ResourceLoaderContext object
+ * @return String: JavaScript code for registering all modules with the
client loader
+ */
+ public static function getModuleRegistrations( ResourceLoaderContext
$context ) {
+ wfProfileIn( __METHOD__ );
+
+ $scripts = '';
+ $registrations = array();
+ foreach ( ResourceLoader::getModules() as $name => $module ) {
+ // Support module loader scripts
+ if ( ( $loader = $module->getLoaderScript() ) !== false
) {
+ $deps = FormatJson::encode(
$module->getDependencies() );
+ $group = FormatJson::encode(
$module->getGroup() );
+ $version = wfTimestamp( TS_ISO_8601, round(
$module->getModifiedTime( $context ), -2 ) );
+ $scripts .= "( function( name, version,
dependencies ) { $loader } )\n" .
+ "( '$name', '$version', $deps, $group
);\n";
+ }
+ // Automatically register module
+ else {
+ // Modules without dependencies or a group pass
two arguments (name, timestamp) to
+ // mediaWiki.loader.register()
+ if ( !count( $module->getDependencies() &&
$module->getGroup() === null ) ) {
+ $registrations[] = array( $name,
$module->getModifiedTime( $context ) );
+ }
+ // Modules with dependencies but no group pass
three arguments (name, timestamp, dependencies)
+ // to mediaWiki.loader.register()
+ else if ( $module->getGroup() === null ) {
+ $registrations[] = array(
+ $name,
$module->getModifiedTime( $context ), $module->getDependencies() );
+ }
+ // Modules with dependencies pass four
arguments (name, timestamp, dependencies, group)
+ // to mediaWiki.loader.register()
+ else {
+ $registrations[] = array(
+ $name,
$module->getModifiedTime( $context ), $module->getDependencies(),
$module->getGroup() );
+ }
+ }
+ }
+ $out = $scripts . "mediaWiki.loader.register( " .
FormatJson::encode( $registrations ) . " );";
+
+ wfProfileOut( __METHOD__ );
+ return $out;
+ }
+
/* Methods */
public function getScript( ResourceLoaderContext $context ) {
global $IP, $wgLoadScript;
$scripts = file_get_contents( "$IP/resources/startup.js" );
-
if ( $context->getOnly() === 'scripts' ) {
// Get all module registrations
- $registration = ResourceLoader::getModuleRegistrations(
$context );
+ $registration = self::getModuleRegistrations( $context
);
// Build configuration
$config = FormatJson::encode( $this->getConfig(
$context ) );
// Add a well-known start-up function
- $scripts .= <<<JAVASCRIPT
-window.startUp = function() {
- $registration
- mediaWiki.config.set( $config );
-};
-JAVASCRIPT;
+ $scripts .= "window.startUp = function()
{\n\t$registration\n\tmediaWiki.config.set( $config );\n};\n";
// Build load query for jquery and mediawiki modules
$query = array(
'modules' => implode( '|', array( 'jquery',
'mediawiki' ) ),
@@ -1074,7 +1116,7 @@
// Build HTML code for loading jquery and mediawiki
modules
$loadScript = Html::linkedScript( $wgLoadScript . '?' .
wfArrayToCGI( $query ) );
// Add code to add jquery and mediawiki loading code;
only if the current client is compatible
- $scripts .= "if ( isCompatible() ) { document.write( "
. FormatJson::encode( $loadScript ) . "); }\n";
+ $scripts .= "if ( isCompatible() ) {\n\tdocument.write(
" . FormatJson::encode( $loadScript ) . ");\n}\n";
// Delete the compatible function - it's not needed
anymore
$scripts .= "delete window['isCompatible'];\n";
}
@@ -1090,10 +1132,10 @@
return $this->modifiedTime[$hash];
}
$this->modifiedTime[$hash] = filemtime(
"$IP/resources/startup.js" );
+
// ATTENTION!: Because of the line above, this is not going to
cause infinite recursion - think carefully
// before making changes to this code!
- $this->modifiedTime[$hash] =
ResourceLoader::getHighestModifiedTime( $context );
- return $this->modifiedTime[$hash];
+ return $this->modifiedTime[$hash] =
ResourceLoader::getHighestModifiedTime( $context );
}
public function getFlip( $context ) {
Modified: trunk/phase3/resources/mediawiki/mediawiki.js
===================================================================
--- trunk/phase3/resources/mediawiki/mediawiki.js 2010-09-24 18:48:20 UTC
(rev 73672)
+++ trunk/phase3/resources/mediawiki/mediawiki.js 2010-09-24 18:49:19 UTC
(rev 73673)
@@ -735,9 +735,10 @@
}
return;
}
- if ( module in registry ) {
- registry[module].state = state;
+ if ( !( module in registry ) ) {
+ that.register( module );
}
+ registry[module].state = state;
};
/**
_______________________________________________
MediaWiki-CVS mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs