http://www.mediawiki.org/wiki/Special:Code/MediaWiki/70428
Revision: 70428 Author: tparscal Date: 2010-08-03 21:23:04 +0000 (Tue, 03 Aug 2010) Log Message: ----------- Made all module options which list files allowed to be given as strings or arrays Modified Paths: -------------- branches/resourceloader/phase3/includes/ResourceLoader.php branches/resourceloader/phase3/resources/Resources.php Modified: branches/resourceloader/phase3/includes/ResourceLoader.php =================================================================== --- branches/resourceloader/phase3/includes/ResourceLoader.php 2010-08-03 21:21:54 UTC (rev 70427) +++ branches/resourceloader/phase3/includes/ResourceLoader.php 2010-08-03 21:23:04 UTC (rev 70428) @@ -25,27 +25,34 @@ * @example * // Registers a module with the resource loading system * ResourceLoader::register( 'foo', array( - * // At minimum you must have a script file + * // Script or list of scripts to include when implementating the module (required) * 'script' => 'resources/foo/foo.js', - * // Optionally you can have a style file as well + * // List of scripts or lists of scripts to include based on the current language + * 'locales' => array( + * 'en-gb' => 'resources/foo/locales/en-gb.js', + * ), + * // Script or list of scripts to include only when in debug mode + * 'debug' => 'resources/foo/debug.js', + * // If this module is going to be loaded before the mediawiki module is ready such as jquery or the mediawiki + * // module itself, it can be included without special loader wrapping - this will also limit the module to not be + * // able to specify needs, custom loaders, styles, themes or messages (any of the options below) - raw scripts + * // get registered as 'ready' after the mediawiki module is ready, so they can be named as dependencies + * 'raw' => false, + * // Modules or list of modules which are needed and should be used when generating loader code + * 'needs' => 'resources/foo/foo.js', + * // Script or list of scripts which will cause loader code to not be generated - if you are doing something fancy + * // with your dependencies this gives you a way to use custom registration code + * 'loader' => 'resources/foo/loader.js', + * // Style-sheets or list of style-sheets to include * 'style' => 'resources/foo/foo.css', - * // List of styles to include based on the skin + * // List of style-sheets or lists of style-sheets to include based on the skin - if no match is found for current + * // skin, 'default' is used - if default doesn't exist nothing is added * 'themes' => array( * 'default' => 'resources/foo/themes/default/foo.css', * 'vector' => 'resources/foo/themes/vector.foo.css', * ), - * // List of scripts to include based on the language - * 'locales' => array( - * 'en-gb' => 'resources/foo/locales/en-gb.js', - * ), - * // Only needed if you are doing something fancy with your loader, otherwise one will be generated for you - * 'loader' => 'resources/foo/loader.js', - * // If you need any localized messages brought into the JavaScript environment, list the keys here + * // List of keys of messages to include * 'messages' => array( 'foo-hello', 'foo-goodbye' ), - * // Raw scripts are are loaded without using the loader and can not bundle loaders, styles and messages - * 'raw' => false, - * // Debug-only scripts are special scripts that are only loaded when requested and while in debug mode - * 'debug' => false, * ) ); * @example * // Responds to a resource loading request @@ -55,6 +62,7 @@ /* Protected Static Members */ + // List of modules and their options protected static $modules = array(); /* Protected Static Methods */ @@ -62,10 +70,10 @@ /** * Runs text through a filter, caching the filtered result for future calls * - * @param string $filter name of filter to run - * @param string $data text to filter, such as JavaScript or CSS text - * @param string $file path to file being filtered, (optional: only required for CSS to resolve paths) - * @return string filtered data + * @param {string} $filter name of filter to run + * @param {string} $data text to filter, such as JavaScript or CSS text + * @param {string} $file path to file being filtered, (optional: only required for CSS to resolve paths) + * @return {string} filtered data */ protected static function filter( $filter, $data, $file = null ) { global $wgMemc; @@ -91,27 +99,99 @@ $wgMemc->set( $key, $result ); return $result; } + /** + * Converts a multi-level array into a flat array containing the unique values of all leaf nodes + * + * @param {array} $deep mutli-level array to flatten + * @param {array} $flat array to append flattened values to (used internally) + * @return {array} flattened array of leaf nodes + */ + protected static function flatten( $deep, $flat = array() ) { + foreach ( $deep as $value ) { + if ( is_array( $value ) ) { + $flat = self::flatten( $value, $flat ); + } else { + if ( $value ) { + $flat[] = $value; + } + } + } + return array_unique( $flat ); + } + /** + * Validates a file or list of files as existing + * + * @param {mixed} string file name or array of any depth containing string file names as leaf nodes + * @throws {MWException} if one or more files do not exist + */ + protected static function validate( $files ) { + if ( is_array( $files ) ) { + $files = self::flatten( $files ); + foreach ( $files as $file ) { + self::validate( $file ); + } + } else { + if ( !file_exists( $files ) ) { + throw new MWException( 'File does not exist: ' . $files ); + } + } + } + /** + * Reads a file or list of files and returns them as a string or outputs them into the current output buffer + * + * @param {mixed} $files string file name or array of any depth containing string file names as leaf nodes + * @param {array} $read list of files which have already been read + * @param + * @return {mixed} string of read data or null if $passthrough is true + */ + protected static function read( $files, $passthrough = false ) { + if ( is_array( $files ) ) { + $files = self::flatten( $files ); + $contents = ''; + foreach ( $files as $file ) { + $contents .= self::read( $file ); + } + return $contents; + } else { + if ( $passthrough ) { + readfile( $files ); + echo "\n"; + return null; + } else { + return file_get_contents( $files ) . "\n"; + } + } + } /* Static Methods */ /** * Registers a module with the ResourceLoader system * - * @param mixed $module string of name of module or array of name/options pairs - * @param array $options module options (optional when using multiple-registration calling style) - * @return boolean false if there were any errors, in which case one or more modules were not registered + * @param {mixed} $module string of name of module or array of name/options pairs + * @param {array} $options module options (optional when using multiple-registration calling style) + * @return {boolean} false if there were any errors, in which case one or more modules were not registered * * $options format: * array( - * 'script' => [string: path to file], - * 'style' => [string: path to file, optional], - * 'themes' => [array: paths to styles to include, keyed by skin name, optional], - * 'locales' => [array: paths to scripts to include, keyed by locale name, optional], - * 'messages' => [array: message keys, optional], - * 'loader' => [string: path to file, optional], - * 'needs' => [array: names of modules this module needs, optional - ignored if loader is present], - * 'raw' => [boolean: include directly without any loading support, optional], - * 'debug' => [boolean: include in debug mode only, optional], + * // Required module options + * 'script' => 'dir/script.js' | array( 'dir/script1.js', 'dir/script2.js' ... ), + * // Optional module options + * 'locales' => array( + * '[locale name]' => 'dir/locale.js' | '[locale name]' => array( 'dir/locale1.js', 'dir/locale2.js' ... ) + * ... + * ), + * 'debug' => 'dir/debug.js' | array( 'dir/debug1.js', 'dir/debug2.js' ... ), + * 'raw' => true | false, + * // Non-raw module options + * 'needs' => 'module' | array( 'module1', 'module2' ... ) + * 'loader' => 'dir/loader.js' | array( 'dir/loader1.js', 'dir/loader2.js' ... ), + * 'style' => 'dir/file.css' | array( 'dir/file1.css', 'dir/file2.css' ... ), + * 'themes' => array( + * '[skin name]' => 'dir/theme.css' | '[skin name]' => array( 'dir/theme1.css', 'dir/theme2.css' ... ) + * ... + * ), + * 'messages' => array( 'message1', 'message2' ... ), * ) * * @todo We need much more clever error reporting, not just in detailing what happened, but in bringing errors to @@ -120,59 +200,57 @@ public static function register( $module, $options = array() ) { // Allow multiple modules to be registered in one call if ( is_array( $module ) && empty( $options ) ) { - $success = true; foreach ( $module as $name => $options ) { - if ( !self::register( $name, $options ) ) { - $success = false; - } + self::register( $name, $options ); } - return $success; + return; } // Disallow duplicate registrations if ( isset( self::$modules[$module] ) ) { // A module has already been registered by this name - return false; + throw new MWException( 'Another module has already been registered as ' . $module ); } - // Always include a set of default options in each registration - more data, less isset() checks + // Always include a set of default options in each registration so we need not exaustively mark all options for + // all modules when registering and also don't need to worry if the options are set or not later on $options = array_merge( array( 'script' => null, - 'style' => null, - 'themes' => array(), - 'locales' => array(), - 'messages' => array(), + 'locales' => null, + 'raw' => false, + // An empty array is used for needs to make json_encode output [] instead of null which is shorted and + // results in easier to work with data on the client + 'needs' => array(), 'loader' => null, - 'needs' => array(), - 'raw' => false, 'debug' => null, + 'style' => null, + 'themes' => null, + 'messages' => null, ), $options ); - // Validate script option + // Validate script option - which is required and must reference files that exist if ( !is_string( $options['script'] ) ) { - // Module does not include a script - return false; + throw new MWException( 'Module does not include a script: ' . $module ); } - if ( !file_exists( $options['script'] ) ) { - // Script file does not exist - return false; + // Validate options that reference files + foreach ( array( 'script', 'locales', 'loader', 'debug', 'style', 'themes' ) as $option ) { + if ( $options[$option] !== null ) { + self::validate( $options[$option] ); + } } - if ( $options['loader'] !== null && !file_exists( $options['loader'] ) ) { - // Loader file does not exist - return false; - } - if ( $options['style'] !== null && !file_exists( $options['style'] ) ) { - // Style file does not exist - return false; - } + // Attach module self::$modules[$module] = $options; } - + /** + * Gets a map of all modules and their options + * + * @return {array} list of modules and their options + */ public static function getModules() { return self::$modules; } - /* * Outputs a response to a resource load-request, including a content-type header * - * @param WebRequest $request web request object to respond to + * @param {WebRequest} $request web request object to respond to + * @param {string} $server web-accessible path to script server * * $options format: * array( @@ -191,6 +269,7 @@ 'lang' => $request->getVal( 'lang', $wgLang->getCode() ), 'skin' => $request->getVal( 'skin', $wgDefaultSkin ), 'debug' => $request->getVal( 'debug' ), + 'server' => $server, ); // Mediawiki's WebRequest::getBool is a bit on the annoying side - we need to allow 'true' and 'false' values // to be converted to boolean true and false @@ -201,24 +280,26 @@ $lang = $wgLang->factory( $parameters['lang'] ); $parameters['dir'] = $lang->getDir(); } - // Get modules - filtering out any we don't know about + // Build a list of requested modules excluding unrecognized ones which are collected into a list used to + // register the unrecognized modules with error status later on $modules = array(); + $missing = array(); foreach ( explode( '|', $request->getVal( 'modules' ) ) as $module ) { if ( isset( self::$modules[$module] ) ) { $modules[] = $module; + } else { + $missing[] = $module; } } // Use output buffering ob_start(); - // Output raw modules first + // Output raw modules first and build a list of raw modules to be registered with ready status later on $ready = array(); foreach ( $modules as $module ) { if ( self::$modules[$module]['raw'] ) { - readfile( self::$modules[$module]['script'] ); - echo "\n"; + self::read( self::$modules[$module]['script'], true ); if ( $parameters['debug'] && self::$modules[$module]['debug'] ) { - readfile( self::$modules[$module]['debug'] ); - echo "\n"; + self::read( self::$modules[$module]['debug'], true ); } $ready[] = $module; } @@ -226,38 +307,36 @@ // Special meta-information for the 'mediawiki' module if ( in_array( 'mediawiki', $modules ) ) { /* - * Skin::makeGlobalVariablesScript needs to be modified so that we still output the globals for now, but also - * put them into the initial payload like this: + * Skin::makeGlobalVariablesScript needs to be modified so that we still output the globals for now, but + * also put them into the initial payload like this: * - * // Sets the inital configuration - * mw.config.set( { 'name': 'value', ... } ); + * // Sets the inital configuration + * mw.config.set( { 'name': 'value', ... } ); * * Also, the naming of these variables is horrible and sad, hopefully this can be worked on */ - $parameters['server'] = $server; echo "mw.config.set( " . json_encode( $parameters ) . " );\n"; - // Collect all loaders + // Generate list of registrations and collect all loader scripts $loaders = array(); $registrations = array(); foreach ( self::$modules as $name => $options ) { - if ( $options['loader'] !== null ) { + if ( $options['loader'] ) { $loaders[] = $options['loader']; } else { - if ( empty( $options['needs'] ) && !in_array( $name, $ready ) ) { + if ( empty( $options['needs'] ) && !in_array( $name, $ready ) && !in_array( $name, $missing ) ) { $registrations[$name] = $name; } else { $registrations[$name] = array( $name, $options['needs'] ); if ( in_array( $name, $ready ) ) { $registrations[$name][] = 'ready'; + } else if ( in_array( $name, $missing ) ) { + $registrations[$name][] = 'missing'; } } } } // Include loaders - foreach ( array_unique( $loaders ) as $loader ) { - readfile( $loader ); - echo "\n"; - } + self::read( $loaders, true ); // Register modules without loaders echo "mw.loader.register( " . json_encode( array_values( $registrations ) ) . " );\n"; } @@ -266,22 +345,22 @@ foreach ( $modules as $module ) { if ( !self::$modules[$module]['raw'] ) { // Script - $script = file_get_contents( self::$modules[$module]['script'] ); + $script = self::read( self::$modules[$module]['script'] ); // Debug if ( $parameters['debug'] && self::$modules[$module]['debug'] ) { - $script .= file_get_contents( self::$modules[$module]['debug'] ); + $script .= self::read( self::$modules[$module]['debug'] ); } // Locale if ( isset( self::$modules[$module]['locales'][$parameters['lang']] ) ) { - $script .= file_get_contents( self::$modules[$module]['locales'][$parameters['lang']] ); + $script .= self::read( self::$modules[$module]['locales'][$parameters['lang']] ); } // Style - $style = self::$modules[$module]['style'] ? file_get_contents( self::$modules[$module]['style'] ) : ''; + $style = self::$modules[$module]['style'] ? self::read( self::$modules[$module]['style'] ) : ''; // Theme if ( isset( self::$modules[$module]['themes'][$parameters['skin']] ) ) { - $style .= file_get_contents( self::$modules[$module]['themes'][$parameters['skin']] ); + $style .= self::read( self::$modules[$module]['themes'][$parameters['skin']] ); } else if ( isset( self::$modules[$module]['themes']['default'] ) ) { - $style .= file_get_contents( self::$modules[$module]['themes']['default'] ); + $style .= self::read( self::$modules[$module]['themes']['default'] ); } if ( $style !== '' ) { if ( $parameters['dir'] == 'rtl' ) { Modified: branches/resourceloader/phase3/resources/Resources.php =================================================================== --- branches/resourceloader/phase3/resources/Resources.php 2010-08-03 21:21:54 UTC (rev 70427) +++ branches/resourceloader/phase3/resources/Resources.php 2010-08-03 21:23:04 UTC (rev 70428) @@ -17,27 +17,33 @@ 'jquery.ui.core' => array( 'script' => 'resources/jquery/ui/jquery.ui.core.js', 'themes' => array( - 'default' => 'resources/jquery/ui/themes/default/jquery.ui.theme.css', - 'vector' => 'resources/jquery/ui/themes/vector/jquery.ui.theme.css', + 'default' => array( + 'resources/jquery/ui/themes/default/jquery.ui.core.css', + 'resources/jquery/ui/themes/default/jquery.ui.theme.css', + ), + 'vector' => array( + 'resources/jquery/ui/themes/vector/jquery.ui.core.css', + 'resources/jquery/ui/themes/vector/jquery.ui.theme.css', + ), ), - 'needs' => array( 'jquery' ), + 'needs' => 'jquery', ), 'jquery.ui.widget' => array( 'script' => 'resources/jquery/ui/jquery.ui.widget.js', - 'needs' => array( 'jquery.ui.core' ), + 'needs' => 'jquery.ui.core', ), 'jquery.ui.mouse' => array( 'script' => 'resources/jquery/ui/jquery.ui.mouse.js', - 'needs' => array( 'jquery' ), + 'needs' => 'jquery', ), 'jquery.ui.position' => array( 'script' => 'resources/jquery/ui/jquery.ui.position.js', - 'needs' => array( 'jquery' ), + 'needs' => 'jquery', ), // Interactions 'jquery.ui.draggable' => array( 'script' => 'resources/jquery/ui/jquery.ui.draggable.js', - 'needs' => array( 'jquery.ui.core' ), + 'needs' => 'jquery.ui.core', ), 'jquery.ui.droppable' => array( 'script' => 'resources/jquery/ui/jquery.ui.droppable.js', @@ -49,7 +55,7 @@ 'default' => 'resources/jquery/ui/themes/default/jquery.ui.resizable.css', 'vector' => 'resources/jquery/ui/themes/vector/jquery.ui.resizable.css', ), - 'needs' => array( 'jquery.ui.core' ), + 'needs' => 'jquery.ui.core', ), 'jquery.ui.selectable' => array( 'script' => 'resources/jquery/ui/jquery.ui.selectable.js', @@ -57,16 +63,16 @@ 'default' => 'resources/jquery/ui/themes/default/jquery.ui.selectable.css', 'vector' => 'resources/jquery/ui/themes/vector/jquery.ui.selectable.css', ), - 'needs' => array( 'jquery.ui.core' ), + 'needs' => 'jquery.ui.core', ), 'jquery.ui.sortable' => array( 'script' => 'resources/jquery/ui/jquery.ui.sortable.js', - 'needs' => array( 'jquery.ui.core' ), + 'needs' => 'jquery.ui.core', ), // Widgets 'jquery.ui.accordion' => array( 'script' => 'resources/jquery/ui/jquery.ui.accordion.js', - 'needs' => array( 'jquery.ui.core' ), + 'needs' => 'jquery.ui.core', 'themes' => array( 'default' => 'resources/jquery/ui/themes/default/jquery.ui.accordion.css', 'vector' => 'resources/jquery/ui/themes/vector/jquery.ui.accordion.css', @@ -90,7 +96,7 @@ ), 'jquery.ui.datepicker' => array( 'script' => 'resources/jquery/ui/jquery.ui.datepicker.js', - 'needs' => array( 'jquery.ui.core' ), + 'needs' => 'jquery.ui.core', 'themes' => array( 'default' => 'resources/jquery/ui/themes/default/jquery.ui.datepicker.css', 'vector' => 'resources/jquery/ui/themes/vector/jquery.ui.datepicker.css', @@ -152,7 +158,7 @@ ), 'jquery.ui.dialog' => array( 'script' => 'resources/jquery/ui/jquery.ui.dialog.js', - 'needs' => array( 'jquery.ui.core' ), + 'needs' => 'jquery.ui.core', 'themes' => array( 'default' => 'resources/jquery/ui/themes/default/jquery.ui.dialog.css', 'vector' => 'resources/jquery/ui/themes/vector/jquery.ui.dialog.css', @@ -160,7 +166,7 @@ ), 'jquery.ui.progressbar' => array( 'script' => 'resources/jquery/ui/jquery.ui.progressbar.js', - 'needs' => array( 'jquery.ui.core' ), + 'needs' => 'jquery.ui.core', 'themes' => array( 'default' => 'resources/jquery/ui/themes/default/jquery.ui.progressbar.css', 'vector' => 'resources/jquery/ui/themes/vector/jquery.ui.progressbar.css', @@ -176,7 +182,7 @@ ), 'jquery.ui.tabs' => array( 'script' => 'resources/jquery/ui/jquery.ui.tabs.js', - 'needs' => array( 'jquery.ui.core' ), + 'needs' => 'jquery.ui.core', 'themes' => array( 'default' => 'resources/jquery/ui/themes/default/jquery.ui.tabs.css', 'vector' => 'resources/jquery/ui/themes/vector/jquery.ui.tabs.css', @@ -185,55 +191,55 @@ // Effects 'jquery.effects.core' => array( 'script' => 'resources/jquery/effects/jquery.effects.core.js', - 'needs' => array( 'jquery' ), + 'needs' => 'jquery', ), 'jquery.effects.blind' => array( 'script' => 'resources/jquery/effects/jquery.effects.blind.js', - 'needs' => array( 'jquery.effects.core' ), + 'needs' => 'jquery.effects.core', ), 'jquery.effects.bounce' => array( 'script' => 'resources/jquery/effects/jquery.effects.bounce.js', - 'needs' => array( 'jquery.effects.core' ), + 'needs' => 'jquery.effects.core', ), 'jquery.effects.clip' => array( 'script' => 'resources/jquery/effects/jquery.effects.clip.js', - 'needs' => array( 'jquery.effects.core' ), + 'needs' => 'jquery.effects.core', ), 'jquery.effects.drop' => array( 'script' => 'resources/jquery/effects/jquery.effects.drop.js', - 'needs' => array( 'jquery.effects.core' ), + 'needs' => 'jquery.effects.core', ), 'jquery.effects.explode' => array( 'script' => 'resources/jquery/effects/jquery.effects.explode.js', - 'needs' => array( 'jquery.effects.core' ), + 'needs' => 'jquery.effects.core', ), 'jquery.effects.fold' => array( 'script' => 'resources/jquery/effects/jquery.effects.fold.js', - 'needs' => array( 'jquery.effects.core' ), + 'needs' => 'jquery.effects.core', ), 'jquery.effects.highlight' => array( 'script' => 'resources/jquery/effects/jquery.effects.highlight.js', - 'needs' => array( 'jquery.effects.core' ), + 'needs' => 'jquery.effects.core', ), 'jquery.effects.pulsate' => array( 'script' => 'resources/jquery/effects/jquery.effects.pulsate.js', - 'needs' => array( 'jquery.effects.core' ), + 'needs' => 'jquery.effects.core', ), 'jquery.effects.scale' => array( 'script' => 'resources/jquery/effects/jquery.effects.scale.js', - 'needs' => array( 'jquery.effects.core' ), + 'needs' => 'jquery.effects.core', ), 'jquery.effects.shake' => array( 'script' => 'resources/jquery/effects/jquery.effects.shake.js', - 'needs' => array( 'jquery.effects.core' ), + 'needs' => 'jquery.effects.core', ), 'jquery.effects.slide' => array( 'script' => 'resources/jquery/effects/jquery.effects.slide.js', - 'needs' => array( 'jquery.effects.core' ), + 'needs' => 'jquery.effects.core', ), 'jquery.effects.transfer' => array( 'script' => 'resources/jquery/effects/jquery.effects.transfer.js', - 'needs' => array( 'jquery.effects.core' ), + 'needs' => 'jquery.effects.core', ), /* MediaWiki */ @@ -248,75 +254,75 @@ 'mediawiki.legacy.ajax' => array( 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.ajax.js', - 'needs' => array( 'mediawiki' ), + 'needs' => 'mediawiki', ), 'mediawiki.legacy.ajaxwatch' => array( 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.ajaxwatch.js', - 'needs' => array( 'mediawiki' ), + 'needs' => 'mediawiki', ), 'mediawiki.legacy.block' => array( 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.block.js', - 'needs' => array( 'mediawiki' ), + 'needs' => 'mediawiki', ), 'mediawiki.legacy.changepassword' => array( 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.changepassword.js', - 'needs' => array( 'mediawiki' ), + 'needs' => 'mediawiki', ), 'mediawiki.legacy.edit' => array( 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.edit.js', - 'needs' => array( 'mediawiki' ), + 'needs' => 'mediawiki', ), 'mediawiki.legacy.enhancedchanges' => array( 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.enhancedchanges.js', - 'needs' => array( 'mediawiki' ), + 'needs' => 'mediawiki', ), 'mediawiki.legacy.history' => array( 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.history.js', - 'needs' => array( 'mediawiki' ), + 'needs' => 'mediawiki', ), 'mediawiki.legacy.htmlform' => array( 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.htmlform.js', - 'needs' => array( 'mediawiki' ), + 'needs' => 'mediawiki', ), 'mediawiki.legacy.IEFixes' => array( 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.IEFixes.js', - 'needs' => array( 'mediawiki' ), + 'needs' => 'mediawiki', ), 'mediawiki.legacy.metadata' => array( 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.metadata.js', - 'needs' => array( 'mediawiki' ), + 'needs' => 'mediawiki', ), 'mediawiki.legacy.mwsuggest' => array( 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.mwsuggest.js', - 'needs' => array( 'mediawiki' ), + 'needs' => 'mediawiki', ), 'mediawiki.legacy.prefs' => array( 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.prefs.js', - 'needs' => array( 'mediawiki' ), + 'needs' => 'mediawiki', ), 'mediawiki.legacy.preview' => array( 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.preview.js', - 'needs' => array( 'mediawiki' ), + 'needs' => 'mediawiki', ), 'mediawiki.legacy.protect' => array( 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.protect.js', - 'needs' => array( 'mediawiki' ), + 'needs' => 'mediawiki', ), 'mediawiki.legacy.rightclickedit' => array( 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.rightclickedit.js', - 'needs' => array( 'mediawiki' ), + 'needs' => 'mediawiki', ), 'mediawiki.legacy.search' => array( 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.search.js', - 'needs' => array( 'mediawiki' ), + 'needs' => 'mediawiki', ), 'mediawiki.legacy.upload' => array( 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.upload.js', - 'needs' => array( 'mediawiki' ), + 'needs' => 'mediawiki', ), 'mediawiki.legacy.wikibits' => array( 'script' => 'resources/mediawiki/legacy/mediawiki.legacy.wikibits.js', - 'needs' => array( 'mediawiki' ), + 'needs' => 'mediawiki', ), /* MediaWiki Utilities */ @@ -338,24 +344,24 @@ 'test' => array( 'script' => 'resources/test/test.js', - 'needs' => array( 'foo' ), + 'needs' => 'foo', 'style' => 'resources/test/test.css', ), 'foo' => array( 'script' => 'resources/test/foo.js', - 'needs' => array( 'bar' ), + 'needs' => 'bar', 'style' => 'resources/test/foo.css', 'messages' => array( 'january', 'february', 'march', 'april', 'may', 'june' ), ), 'bar' => array( 'script' => 'resources/test/bar.js', - 'needs' => array( 'buz' ), + 'needs' => 'buz', 'style' => 'resources/test/bar.css', 'messages' => array( 'july', 'august', 'september', 'october', 'november', 'december' ), ), 'buz' => array( 'script' => 'resources/test/buz.js', - 'needs' => array( 'baz' ), + 'needs' => 'baz', 'style' => 'resources/test/buz.css', ), 'baz' => array( _______________________________________________ MediaWiki-CVS mailing list MediaWiki-CVS@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs