From dac5084f6d61b6c45bfae491a2b91d96f61ad778 Mon Sep 17 00:00:00 2001 From: Tim Starling Date: Fri, 19 Nov 2010 10:41:06 +0000 Subject: [PATCH] * Made Resources.php return a pure-data array instead of an ugly mix of data and code. This allows the class code to be lazy-loaded with the autoloader, for a performance advantage especially on non-APC installs. And using the convention where if the class is omitted, ResourceLoaderFileModule is assumed, the registration code becomes shorter and simpler. * Modified ResourceLoader to lazy-initialise module objects, for a further performance advantage. * Deleted ResourceLoader::getModules(), provided getModuleNames() instead. Although the startup module needs this functionality, it's slow to generate, so to avoid misuse, it's better to provide a foolproof fast interface and let the startup module do the slow thing itself. * Modified ResourceLoader::register() to optionally accept an info array instead of an object. * Added $wgResourceModules, allowing extensions to efficiently define their own resource loader modules. The trouble with hooks is that they contain code, and code is slow. We've been through all this before with i18n. Hooks are useful as a performance tool only if you call them very rarely. * Moved ResourceLoader settings to their own section in DefaultSettings.php * Added options to ResourceLoaderFileModule equivalent to the $localBasePath and $remoteBasePath parameters, to allow it to be instantiated via the new array style. Also added remoteExtPath, which allows modules to be registered before $wgExtensionAssetsPath is known. * Added OutputPage::getResourceLoader(), mostly for debugging. * The time saving at the moment is about 5ms per request with no extensions, which is significant already with 6 load.php requests for a cold cache page view. This is a much more scalable interface; the relative saving will grow as more extensions are added which use this interface, especially for non-APC installs. Although the interface is backwards compatible, extension updates will follow in a subsequent commit. --- includes/DefaultSettings.php | 95 +++-- includes/OutputPage.php | 24 +- includes/resourceloader/ResourceLoader.php | 92 +++-- .../ResourceLoaderFileModule.php | 14 + .../ResourceLoaderStartUpModule.php | 8 +- resources/Resources.php | 342 +++++++++--------- 6 files changed, 324 insertions(+), 251 deletions(-) diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index cda21f9b47..c4014d67f0 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -1646,42 +1646,6 @@ $wgUseETag = false; */ $wgClockSkewFudge = 5; -/** - * Maximum time in seconds to cache resources served by the resource loader - */ -$wgResourceLoaderMaxage = array( - 'versioned' => array( - // Squid/Varnish but also any other public proxy cache between the client and MediaWiki - 'server' => 30 * 24 * 60 * 60, // 30 days - // On the client side (e.g. in the browser cache). - 'client' => 30 * 24 * 60 * 60, // 30 days - ), - 'unversioned' => array( - 'server' => 5 * 60, // 5 minutes - 'client' => 5 * 60, // 5 minutes - ), -); - -/** - * Whether to embed private modules inline with HTML output or to bypass - * caching and check the user parameter against $wgUser to prevent - * unauthorized access to private modules. - */ -$wgResourceLoaderInlinePrivateModules = true; - -/** - * The default debug mode (on/off) for of ResourceLoader requests. This will still - * be overridden when the debug URL parameter is used. - */ -$wgResourceLoaderDebug = false; - -/** - * Enable embedding of certain resources using Edge Side Includes. This will - * improve performance but only works if there is something in front of the - * web server (e..g a Squid or Varnish server) configured to process the ESI. - */ -$wgResourceLoaderUseESI = false; - /** @} */ # end of cache settings /************************************************************************//** @@ -2319,6 +2283,65 @@ $wgBetterDirectionality = false; /** @} */ # End of output format settings } +/*************************************************************************//** + * @name Resource loader settings + * @{ + */ + +/** + * Client-side resource modules. Extensions should add their module definitions + * here. + * + * Example: + * $wgResourceModules['ext.myExtension'] = array( + * 'scripts' => 'myExtension.js', + * 'styles' => 'myExtension.css', + * 'dependencies' => array( 'jquery.cookie', 'jquery.tabIndex' ), + * 'localBasePath' => dirname( __FILE ), + * 'remoteExtPath' => 'MyExtension', + * ); + */ +$wgResourceModules = array(); + +/** + * Maximum time in seconds to cache resources served by the resource loader + */ +$wgResourceLoaderMaxage = array( + 'versioned' => array( + // Squid/Varnish but also any other public proxy cache between the client and MediaWiki + 'server' => 30 * 24 * 60 * 60, // 30 days + // On the client side (e.g. in the browser cache). + 'client' => 30 * 24 * 60 * 60, // 30 days + ), + 'unversioned' => array( + 'server' => 5 * 60, // 5 minutes + 'client' => 5 * 60, // 5 minutes + ), +); + +/** + * Whether to embed private modules inline with HTML output or to bypass + * caching and check the user parameter against $wgUser to prevent + * unauthorized access to private modules. + */ +$wgResourceLoaderInlinePrivateModules = true; + +/** + * The default debug mode (on/off) for of ResourceLoader requests. This will still + * be overridden when the debug URL parameter is used. + */ +$wgResourceLoaderDebug = false; + +/** + * Enable embedding of certain resources using Edge Side Includes. This will + * improve performance but only works if there is something in front of the + * web server (e..g a Squid or Varnish server) configured to process the ESI. + */ +$wgResourceLoaderUseESI = false; + +/** @} */ # End of resource loader settings } + + /*************************************************************************//** * @name Page title and interwiki link settings * @{ diff --git a/includes/OutputPage.php b/includes/OutputPage.php index 9c2f99263f..a80d4eb89c 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -2289,6 +2289,16 @@ class OutputPage { return $ret; } + /** + * Get a ResourceLoader object associated with this OutputPage + */ + public function getResourceLoader() { + if ( is_null( $this->mResourceLoader ) ) { + $this->mResourceLoader = new ResourceLoader(); + } + return $this->mResourceLoader; + } + /** * TODO: Document * @param $skin Skin @@ -2301,9 +2311,6 @@ class OutputPage { global $wgUser, $wgLang, $wgLoadScript, $wgResourceLoaderUseESI, $wgResourceLoaderInlinePrivateModules; // Lazy-load ResourceLoader - if ( is_null( $this->mResourceLoader ) ) { - $this->mResourceLoader = new ResourceLoader(); - } // TODO: Should this be a static function of ResourceLoader instead? // TODO: Divide off modules starting with "user", and add the user parameter to them $query = array( @@ -2335,8 +2342,9 @@ class OutputPage { // Create keyed-by-group list of module objects from modules list $groups = array(); + $resourceLoader = $this->getResourceLoader(); foreach ( (array) $modules as $name ) { - $module = $this->mResourceLoader->getModule( $name ); + $module = $resourceLoader->getModule( $name ); $group = $module->getGroup(); if ( !isset( $groups[$group] ) ) { $groups[$group] = array(); @@ -2352,15 +2360,15 @@ class OutputPage { } // Support inlining of private modules if configured as such if ( $group === 'private' && $wgResourceLoaderInlinePrivateModules ) { - $context = new ResourceLoaderContext( $this->mResourceLoader, new FauxRequest( $query ) ); + $context = new ResourceLoaderContext( $resourceLoader, new FauxRequest( $query ) ); if ( $only == 'styles' ) { $links .= Html::inlineStyle( - $this->mResourceLoader->makeModuleResponse( $context, $modules ) + $resourceLoader->makeModuleResponse( $context, $modules ) ); } else { $links .= Html::inlineScript( ResourceLoader::makeLoaderConditionalScript( - $this->mResourceLoader->makeModuleResponse( $context, $modules ) + $resourceLoader->makeModuleResponse( $context, $modules ) ) ); } @@ -2371,7 +2379,7 @@ class OutputPage { // we can ensure cache misses on change if ( $group === 'user' || $group === 'site' ) { // Create a fake request based on the one we are about to make so modules return correct times - $context = new ResourceLoaderContext( $this->mResourceLoader, new FauxRequest( $query ) ); + $context = new ResourceLoaderContext( $resourceLoader, new FauxRequest( $query ) ); // Get the maximum timestamp $timestamp = 1; foreach ( $modules as $module ) { diff --git a/includes/resourceloader/ResourceLoader.php b/includes/resourceloader/ResourceLoader.php index 5a9d22059c..677543ca2c 100644 --- a/includes/resourceloader/ResourceLoader.php +++ b/includes/resourceloader/ResourceLoader.php @@ -32,6 +32,8 @@ class ResourceLoader { /** Array: List of module name/ResourceLoaderModule object pairs */ protected $modules = array(); + /** Associative array mapping module name to info associative array */ + protected $moduleInfos = array(); /* Protected Methods */ @@ -67,7 +69,7 @@ class ResourceLoader { // Set modules' dependecies $modulesWithDeps = array(); foreach ( $res as $row ) { - $this->modules[$row->md_module]->setFileDependencies( $skin, + $this->getModule( $row->md_module )->setFileDependencies( $skin, FormatJson::decode( $row->md_deps, true ) ); $modulesWithDeps[] = $row->md_module; @@ -75,14 +77,14 @@ class ResourceLoader { // Register the absence of a dependency row too foreach ( array_diff( $modules, $modulesWithDeps ) as $name ) { - $this->modules[$name]->setFileDependencies( $skin, array() ); + $this->getModule( $name )->setFileDependencies( $skin, array() ); } // Get message blob mtimes. Only do this for modules with messages $modulesWithMessages = array(); $modulesWithoutMessages = array(); foreach ( $modules as $name ) { - if ( count( $this->modules[$name]->getMessages() ) ) { + if ( count( $this->getModule( $name )->getMessages() ) ) { $modulesWithMessages[] = $name; } else { $modulesWithoutMessages[] = $name; @@ -95,11 +97,11 @@ class ResourceLoader { ), __METHOD__ ); foreach ( $res as $row ) { - $this->modules[$row->mr_resource]->setMsgBlobMtime( $lang, $row->mr_timestamp ); + $this->getModule( $row->mr_resource )->setMsgBlobMtime( $lang, $row->mr_timestamp ); } } foreach ( $modulesWithoutMessages as $name ) { - $this->modules[$name]->setMsgBlobMtime( $lang, 0 ); + $this->getModule( $name )->setMsgBlobMtime( $lang, 0 ); } } @@ -172,7 +174,7 @@ class ResourceLoader { * Registers core modules and runs registration hooks. */ public function __construct() { - global $IP; + global $IP, $wgResourceModules; wfProfileIn( __METHOD__ ); @@ -180,6 +182,7 @@ class ResourceLoader { $this->register( include( "$IP/resources/Resources.php" ) ); // Register extension modules wfRunHooks( 'ResourceLoaderRegisterModules', array( &$this ) ); + $this->register( $wgResourceModules ); wfProfileOut( __METHOD__ ); } @@ -188,30 +191,27 @@ class ResourceLoader { * Registers a module with the ResourceLoader system. * * @param $name Mixed: Name of module as a string or List of name/object pairs as an array - * @param $object ResourceLoaderModule: Module object (optional when using - * multiple-registration calling style) + * @param $info Module info array. For backwards compatibility with 1.17alpha, + * this may also be a ResourceLoaderModule object. Optional when using + * multiple-registration calling style. * @throws MWException: If a duplicate module registration is attempted * @throws MWException: If something other than a ResourceLoaderModule is being registered * @return Boolean: False if there were any errors, in which case one or more modules were not * registered */ - public function register( $name, ResourceLoaderModule $object = null ) { - + public function register( $name, $info = null ) { wfProfileIn( __METHOD__ ); // Allow multiple modules to be registered in one call - if ( is_array( $name ) && !isset( $object ) ) { + if ( is_array( $name ) ) { foreach ( $name as $key => $value ) { $this->register( $key, $value ); } - - wfProfileOut( __METHOD__ ); - return; } // Disallow duplicate registrations - if ( isset( $this->modules[$name] ) ) { + if ( isset( $this->moduleInfos[$name] ) ) { // A module has already been registered by this name throw new MWException( 'ResourceLoader duplicate registration error. ' . @@ -219,26 +219,32 @@ class ResourceLoader { ); } - // Validate the input (type hinting lets null through) - if ( !( $object instanceof ResourceLoaderModule ) ) { - throw new MWException( 'ResourceLoader invalid module error. ' . - 'Instances of ResourceLoaderModule expected.' ); + // Attach module + if ( is_object( $info ) ) { + // Old calling convention + // Validate the input + if ( !( $info instanceof ResourceLoaderModule ) ) { + throw new MWException( 'ResourceLoader invalid module error. ' . + 'Instances of ResourceLoaderModule expected.' ); + } + + $this->moduleInfos[$name] = array( 'object' => $info ); + $this->modules[$name] = $info; + } else { + // New calling convention + $this->moduleInfos[$name] = $info; } - // Attach module - $this->modules[$name] = $object; - $object->setName( $name ); - wfProfileOut( __METHOD__ ); } - /** - * Gets a map of all modules and their options + /** + * Get a list of module names * - * @return Array: List of modules keyed by module name + * @return Array: List of module names */ - public function getModules() { - return $this->modules; + public function getModuleNames() { + return array_keys( $this->moduleInfos ); } /** @@ -248,7 +254,29 @@ class ResourceLoader { * @return Mixed: ResourceLoaderModule if module has been registered, null otherwise */ public function getModule( $name ) { - return isset( $this->modules[$name] ) ? $this->modules[$name] : null; + if ( !isset( $this->modules[$name] ) ) { + if ( !isset( $this->moduleInfos[$name] ) ) { + // No such module + return null; + } + // Construct the requested object + $info = $this->moduleInfos[$name]; + if ( isset( $info['object'] ) ) { + // Object given in info array + $object = $info['object']; + } else { + if ( !isset( $info['class'] ) ) { + $class = 'ResourceLoaderFileModule'; + } else { + $class = $info['class']; + } + $object = new $class( $info ); + } + $object->setName( $name ); + $this->modules[$name] = $object; + } + + return $this->modules[$name]; } /** @@ -265,8 +293,8 @@ class ResourceLoader { $modules = array(); $missing = array(); foreach ( $context->getModules() as $name ) { - if ( isset( $this->modules[$name] ) ) { - $modules[$name] = $this->modules[$name]; + if ( isset( $this->moduleInfos[$name] ) ) { + $modules[$name] = $this->getModule( $name ); } else { $missing[] = $name; } @@ -376,7 +404,7 @@ class ResourceLoader { if ( $context->shouldIncludeStyles() ) { $styles = $module->getStyles( $context ); // Flip CSS on a per-module basis - if ( $styles && $this->modules[$name]->getFlip( $context ) ) { + if ( $styles && $module->getFlip( $context ) ) { foreach ( $styles as $media => $style ) { $styles[$media] = $this->filter( 'flip-css', $style ); } diff --git a/includes/resourceloader/ResourceLoaderFileModule.php b/includes/resourceloader/ResourceLoaderFileModule.php index 84136012d2..b569d253b5 100644 --- a/includes/resourceloader/ResourceLoaderFileModule.php +++ b/includes/resourceloader/ResourceLoaderFileModule.php @@ -105,6 +105,12 @@ class ResourceLoaderFileModule extends ResourceLoaderModule { * * @example $options * array( + * // Base path to prepend to all local paths in $options. Defaults to $IP + * 'localBasePath' => [base path], + * // Base path to prepend to all remote paths in $options. Defaults to $wgScriptPath + * 'remoteBasePath' => [base path], + * // Equivalent of remoteBasePath, but relative to $wgExtensionAssetsPath + * 'remoteExtPath' => [base path], * // Scripts to always include * 'scripts' => [file path string or array of file path strings], * // Scripts to include in specific language contexts @@ -139,6 +145,12 @@ class ResourceLoaderFileModule extends ResourceLoaderModule { global $IP, $wgScriptPath; $this->localBasePath = $localBasePath === null ? $IP : $localBasePath; $this->remoteBasePath = $remoteBasePath === null ? $wgScriptPath : $remoteBasePath; + + if ( isset( $options['remoteExtPath'] ) ) { + global $wgExtensionAssetsPath; + $this->remoteBasePath = $wgExtensionAssetsPath . '/' . $options['remoteExtPath']; + } + foreach ( $options as $member => $option ) { switch ( $member ) { // Lists of file paths @@ -175,6 +187,8 @@ class ResourceLoaderFileModule extends ResourceLoaderModule { break; // Single strings case 'group': + case 'localBasePath': + case 'remoteBasePath': $this->{$member} = (string) $option; break; // Single booleans diff --git a/includes/resourceloader/ResourceLoaderStartUpModule.php b/includes/resourceloader/ResourceLoaderStartUpModule.php index 718831e5d4..f0c1e80f85 100644 --- a/includes/resourceloader/ResourceLoaderStartUpModule.php +++ b/includes/resourceloader/ResourceLoaderStartUpModule.php @@ -101,7 +101,9 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule { $out = ''; $registrations = array(); - foreach ( $context->getResourceLoader()->getModules() as $name => $module ) { + $resourceLoader = $context->getResourceLoader(); + foreach ( $resourceLoader->getModuleNames() as $name ) { + $module = $resourceLoader->getModule( $name ); // Support module loader scripts $loader = $module->getLoaderScript(); if ( $loader !== false ) { @@ -193,7 +195,9 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule { // infinite recursion - think carefully before making changes to this // code! $time = wfTimestamp( TS_UNIX, $wgCacheEpoch ); - foreach ( $context->getResourceLoader()->getModules() as $module ) { + $loader = $context->getResourceLoader(); + foreach ( $loader->getModuleNames() as $name ) { + $module = $loader->getModule( $name ); $time = max( $time, $module->getModifiedTime( $context ) ); } return $this->modifiedTime[$hash] = $time; diff --git a/resources/Resources.php b/resources/Resources.php index 84dc0c34df..9af4c7d53f 100644 --- a/resources/Resources.php +++ b/resources/Resources.php @@ -4,89 +4,85 @@ return array( /* Special resources who have their own classes */ - 'site' => new ResourceLoaderSiteModule, - 'startup' => new ResourceLoaderStartUpModule, - 'user' => new ResourceLoaderUserModule, - 'user.options' => new ResourceLoaderUserOptionsModule, + 'site' => array( 'class' => 'ResourceLoaderSiteModule' ), + 'startup' => array( 'class' => 'ResourceLoaderStartUpModule' ), + 'user' => array( 'class' => 'ResourceLoaderUserModule' ), + 'user.options' => array( 'class' => 'ResourceLoaderUserOptionsModule' ), /* Skins */ - 'skins.vector' => new ResourceLoaderFileModule( - array( 'styles' => array( 'skins/vector/screen.css' => array( 'media' => 'screen' ) ) ) - ), - 'skins.monobook' => new ResourceLoaderFileModule( - array( 'styles' => array( - 'skins/monobook/main.css' => array( 'media' => 'screen' ), - // Honor $wgHandheldStyle. This is kind of evil - //$GLOBALS['wgHandheldStyle'] => array( 'media' => 'handheld' ) - ) + 'skins.vector' => array( + 'styles' => array( 'skins/vector/screen.css' => array( 'media' => 'screen' ) ) + ), + 'skins.monobook' => array( + 'styles' => array( + 'skins/monobook/main.css' => array( 'media' => 'screen' ), + // Honor $wgHandheldStyle. This is kind of evil + //$GLOBALS['wgHandheldStyle'] => array( 'media' => 'handheld' ) ) ), /* jQuery */ - 'jquery' => new ResourceLoaderFileModule( - array( 'scripts' => 'resources/jquery/jquery.js', 'debugRaw' => false ) + 'jquery' => array( + 'scripts' => 'resources/jquery/jquery.js', + 'debugRaw' => false ), /* jQuery Plugins */ - 'jquery.async' => new ResourceLoaderFileModule( - array( 'scripts' => 'resources/jquery/jquery.async.js' ) + 'jquery.async' => array( + 'scripts' => 'resources/jquery/jquery.async.js' ), - 'jquery.autoEllipsis' => new ResourceLoaderFileModule( - array( 'scripts' => 'resources/jquery/jquery.autoEllipsis.js' ) + 'jquery.autoEllipsis' => array( + 'scripts' => 'resources/jquery/jquery.autoEllipsis.js' ), - 'jquery.checkboxShiftClick' => new ResourceLoaderFileModule( - array( 'scripts' => 'resources/jquery/jquery.checkboxShiftClick.js' ) + 'jquery.checkboxShiftClick' => array( + 'scripts' => 'resources/jquery/jquery.checkboxShiftClick.js' ), - 'jquery.client' => new ResourceLoaderFileModule( - array( 'scripts' => 'resources/jquery/jquery.client.js' ) + 'jquery.client' => array( + 'scripts' => 'resources/jquery/jquery.client.js', ), - 'jquery.collapsibleTabs' => new ResourceLoaderFileModule( - array( 'scripts' => 'resources/jquery/jquery.collapsibleTabs.js' ) + 'jquery.collapsibleTabs' => array( + 'scripts' => 'resources/jquery/jquery.collapsibleTabs.js' ), - 'jquery.color' => new ResourceLoaderFileModule( - array( 'scripts' => 'resources/jquery/jquery.color.js' ) + 'jquery.color' => array( + 'scripts' => 'resources/jquery/jquery.color.js' ), - 'jquery.cookie' => new ResourceLoaderFileModule( - array( 'scripts' => 'resources/jquery/jquery.cookie.js' ) + 'jquery.cookie' => array( + 'scripts' => 'resources/jquery/jquery.cookie.js' ), - 'jquery.delayedBind' => new ResourceLoaderFileModule( - array( 'scripts' => 'resources/jquery/jquery.delayedBind.js' ) + 'jquery.delayedBind' => array( + 'scripts' => 'resources/jquery/jquery.delayedBind.js' ), - 'jquery.expandableField' => new ResourceLoaderFileModule( - array( 'scripts' => 'resources/jquery/jquery.expandableField.js' ) + 'jquery.expandableField' => array( + 'scripts' => 'resources/jquery/jquery.expandableField.js' ), - 'jquery.highlightText' => new ResourceLoaderFileModule( - array( 'scripts' => 'resources/jquery/jquery.highlightText.js' ) + 'jquery.highlightText' => array( + 'scripts' => 'resources/jquery/jquery.highlightText.js' ), - 'jquery.placeholder' => new ResourceLoaderFileModule( - array( 'scripts' => 'resources/jquery/jquery.placeholder.js' ) + 'jquery.placeholder' => array( + 'scripts' => 'resources/jquery/jquery.placeholder.js' ), - 'jquery.suggestions' => new ResourceLoaderFileModule( - array( - 'scripts' => 'resources/jquery/jquery.suggestions.js', - 'styles' => 'resources/jquery/jquery.suggestions.css', - ) + 'jquery.suggestions' => array( + 'scripts' => 'resources/jquery/jquery.suggestions.js', + 'styles' => 'resources/jquery/jquery.suggestions.css', ), - 'jquery.tabIndex' => new ResourceLoaderFileModule( - array( 'scripts' => 'resources/jquery/jquery.tabIndex.js' ) + 'jquery.tabIndex' => array( + 'scripts' => 'resources/jquery/jquery.tabIndex.js' ), - 'jquery.textSelection' => new ResourceLoaderFileModule( - array( 'scripts' => 'resources/jquery/jquery.textSelection.js' ) + 'jquery.textSelection' => array( + 'scripts' => 'resources/jquery/jquery.textSelection.js' ), - 'jquery.tipsy' => new ResourceLoaderFileModule( - array( - 'scripts' => 'resources/jquery.tipsy/jquery.tipsy.js', - 'styles' => 'resources/jquery.tipsy/jquery.tipsy.css', - ) + 'jquery.tipsy' => array( + 'scripts' => 'resources/jquery.tipsy/jquery.tipsy.js', + 'styles' => 'resources/jquery.tipsy/jquery.tipsy.css', ), /* jQuery UI */ // Core - 'jquery.ui.core' => new ResourceLoaderFileModule( array( + 'jquery.ui.core' => array( 'scripts' => 'resources/jquery.ui/jquery.ui.core.js', 'skinStyles' => array( 'default' => array( @@ -99,74 +95,74 @@ return array( ), ), 'dependencies' => 'jquery', - ) ), - 'jquery.ui.widget' => new ResourceLoaderFileModule( array( + ), + 'jquery.ui.widget' => array( 'scripts' => 'resources/jquery.ui/jquery.ui.widget.js', - ) ), - 'jquery.ui.mouse' => new ResourceLoaderFileModule( array( + ), + 'jquery.ui.mouse' => array( 'scripts' => 'resources/jquery.ui/jquery.ui.mouse.js', 'dependencies' => 'jquery.ui.widget', - ) ), - 'jquery.ui.position' => new ResourceLoaderFileModule( array( + ), + 'jquery.ui.position' => array( 'scripts' => 'resources/jquery.ui/jquery.ui.position.js', - ) ), + ), // Interactions - 'jquery.ui.draggable' => new ResourceLoaderFileModule( array( + 'jquery.ui.draggable' => array( 'scripts' => 'resources/jquery.ui/jquery.ui.draggable.js', 'dependencies' => array( 'jquery.ui.core', 'jquery.ui.mouse', 'jquery.ui.widget' ), - ) ), - 'jquery.ui.droppable' => new ResourceLoaderFileModule( array( + ), + 'jquery.ui.droppable' => array( 'scripts' => 'resources/jquery.ui/jquery.ui.droppable.js', 'dependencies' => array( 'jquery.ui.core', 'jquery.ui.mouse', 'jquery.ui.widget', 'jquery.ui.draggable' ), - ) ), - 'jquery.ui.resizable' => new ResourceLoaderFileModule( array( + ), + 'jquery.ui.resizable' => array( 'scripts' => 'resources/jquery.ui/jquery.ui.resizable.js', 'skinStyles' => array( 'default' => 'resources/jquery.ui/themes/default/jquery.ui.resizable.css', 'vector' => 'resources/jquery.ui/themes/vector/jquery.ui.resizable.css', ), 'dependencies' => array( 'jquery.ui.core', 'jquery.ui.widget', 'jquery.ui.mouse' ), - ) ), - 'jquery.ui.selectable' => new ResourceLoaderFileModule( array( + ), + 'jquery.ui.selectable' => array( 'scripts' => 'resources/jquery.ui/jquery.ui.selectable.js', 'skinStyles' => array( 'default' => 'resources/jquery.ui/themes/default/jquery.ui.selectable.css', 'vector' => 'resources/jquery.ui/themes/vector/jquery.ui.selectable.css', ), 'dependencies' => array( 'jquery.ui.core', 'jquery.ui.widget', 'jquery.ui.mouse' ), - ) ), - 'jquery.ui.sortable' => new ResourceLoaderFileModule( array( + ), + 'jquery.ui.sortable' => array( 'scripts' => 'resources/jquery.ui/jquery.ui.sortable.js', 'dependencies' => array( 'jquery.ui.core', 'jquery.ui.widget', 'jquery.ui.mouse' ), - ) ), + ), // Widgets - 'jquery.ui.accordion' => new ResourceLoaderFileModule( array( + 'jquery.ui.accordion' => array( 'scripts' => 'resources/jquery.ui/jquery.ui.accordion.js', 'dependencies' => array( 'jquery.ui.core', 'jquery.ui.widget' ), 'skinStyles' => array( 'default' => 'resources/jquery.ui/themes/default/jquery.ui.accordion.css', 'vector' => 'resources/jquery.ui/themes/vector/jquery.ui.accordion.css', ), - ) ), - 'jquery.ui.autocomplete' => new ResourceLoaderFileModule( array( + ), + 'jquery.ui.autocomplete' => array( 'scripts' => 'resources/jquery.ui/jquery.ui.autocomplete.js', 'dependencies' => array( 'jquery.ui.core', 'jquery.ui.widget', 'jquery.ui.position' ), 'skinStyles' => array( 'default' => 'resources/jquery.ui/themes/default/jquery.ui.autocomplete.css', 'vector' => 'resources/jquery.ui/themes/vector/jquery.ui.autocomplete.css', ), - ) ), - 'jquery.ui.button' => new ResourceLoaderFileModule( array( + ), + 'jquery.ui.button' => array( 'scripts' => 'resources/jquery.ui/jquery.ui.button.js', 'dependencies' => array( 'jquery.ui.core', 'jquery.ui.widget' ), 'skinStyles' => array( 'default' => 'resources/jquery.ui/themes/default/jquery.ui.button.css', 'vector' => 'resources/jquery.ui/themes/vector/jquery.ui.button.css', ), - ) ), - 'jquery.ui.datepicker' => new ResourceLoaderFileModule( array( + ), + 'jquery.ui.datepicker' => array( 'scripts' => 'resources/jquery.ui/jquery.ui.datepicker.js', 'dependencies' => 'jquery.ui.core', 'skinStyles' => array( @@ -227,8 +223,8 @@ return array( 'zh-hk' => 'resources/jquery.ui/i18n/jquery.ui.datepicker-zh-HK.js', 'zh-tw' => 'resources/jquery.ui/i18n/jquery.ui.datepicker-zh-TW.js' ), - ) ), - 'jquery.ui.dialog' => new ResourceLoaderFileModule( array( + ), + 'jquery.ui.dialog' => array( 'scripts' => 'resources/jquery.ui/jquery.ui.dialog.js', 'dependencies' => array( 'jquery.ui.core', @@ -243,112 +239,112 @@ return array( 'default' => 'resources/jquery.ui/themes/default/jquery.ui.dialog.css', 'vector' => 'resources/jquery.ui/themes/vector/jquery.ui.dialog.css', ), - ) ), - 'jquery.ui.progressbar' => new ResourceLoaderFileModule( array( + ), + 'jquery.ui.progressbar' => array( 'scripts' => 'resources/jquery.ui/jquery.ui.progressbar.js', 'dependencies' => array( 'jquery.ui.core', 'jquery.ui.widget' ), 'skinStyles' => array( 'default' => 'resources/jquery.ui/themes/default/jquery.ui.progressbar.css', 'vector' => 'resources/jquery.ui/themes/vector/jquery.ui.progressbar.css', ), - ) ), - 'jquery.ui.slider' => new ResourceLoaderFileModule( array( + ), + 'jquery.ui.slider' => array( 'scripts' => 'resources/jquery.ui/jquery.ui.slider.js', 'dependencies' => array( 'jquery.ui.core', 'jquery.ui.widget', 'jquery.ui.mouse' ), 'skinStyles' => array( 'default' => 'resources/jquery.ui/themes/default/jquery.ui.slider.css', 'vector' => 'resources/jquery.ui/themes/vector/jquery.ui.slider.css', ), - ) ), - 'jquery.ui.tabs' => new ResourceLoaderFileModule( array( + ), + 'jquery.ui.tabs' => array( 'scripts' => 'resources/jquery.ui/jquery.ui.tabs.js', 'dependencies' => array( 'jquery.ui.core', 'jquery.ui.widget' ), 'skinStyles' => array( 'default' => 'resources/jquery.ui/themes/default/jquery.ui.tabs.css', 'vector' => 'resources/jquery.ui/themes/vector/jquery.ui.tabs.css', ), - ) ), + ), // Effects - 'jquery.effects.core' => new ResourceLoaderFileModule( array( + 'jquery.effects.core' => array( 'scripts' => 'resources/jquery.effects/jquery.effects.core.js', 'dependencies' => 'jquery', - ) ), - 'jquery.effects.blind' => new ResourceLoaderFileModule( array( + ), + 'jquery.effects.blind' => array( 'scripts' => 'resources/jquery.effects/jquery.effects.blind.js', 'dependencies' => 'jquery.effects.core', - ) ), - 'jquery.effects.bounce' => new ResourceLoaderFileModule( array( + ), + 'jquery.effects.bounce' => array( 'scripts' => 'resources/jquery.effects/jquery.effects.bounce.js', 'dependencies' => 'jquery.effects.core', - ) ), - 'jquery.effects.clip' => new ResourceLoaderFileModule( array( + ), + 'jquery.effects.clip' => array( 'scripts' => 'resources/jquery.effects/jquery.effects.clip.js', 'dependencies' => 'jquery.effects.core', - ) ), - 'jquery.effects.drop' => new ResourceLoaderFileModule( array( + ), + 'jquery.effects.drop' => array( 'scripts' => 'resources/jquery.effects/jquery.effects.drop.js', 'dependencies' => 'jquery.effects.core', - ) ), - 'jquery.effects.explode' => new ResourceLoaderFileModule( array( + ), + 'jquery.effects.explode' => array( 'scripts' => 'resources/jquery.effects/jquery.effects.explode.js', 'dependencies' => 'jquery.effects.core', - ) ), - 'jquery.effects.fold' => new ResourceLoaderFileModule( array( + ), + 'jquery.effects.fold' => array( 'scripts' => 'resources/jquery.effects/jquery.effects.fold.js', 'dependencies' => 'jquery.effects.core', - ) ), - 'jquery.effects.highlight' => new ResourceLoaderFileModule( array( + ), + 'jquery.effects.highlight' => array( 'scripts' => 'resources/jquery.effects/jquery.effects.highlight.js', 'dependencies' => 'jquery.effects.core', - ) ), - 'jquery.effects.pulsate' => new ResourceLoaderFileModule( array( + ), + 'jquery.effects.pulsate' => array( 'scripts' => 'resources/jquery.effects/jquery.effects.pulsate.js', 'dependencies' => 'jquery.effects.core', - ) ), - 'jquery.effects.scale' => new ResourceLoaderFileModule( array( + ), + 'jquery.effects.scale' => array( 'scripts' => 'resources/jquery.effects/jquery.effects.scale.js', 'dependencies' => 'jquery.effects.core', - ) ), - 'jquery.effects.shake' => new ResourceLoaderFileModule( array( + ), + 'jquery.effects.shake' => array( 'scripts' => 'resources/jquery.effects/jquery.effects.shake.js', 'dependencies' => 'jquery.effects.core', - ) ), - 'jquery.effects.slide' => new ResourceLoaderFileModule( array( + ), + 'jquery.effects.slide' => array( 'scripts' => 'resources/jquery.effects/jquery.effects.slide.js', 'dependencies' => 'jquery.effects.core', - ) ), - 'jquery.effects.transfer' => new ResourceLoaderFileModule( array( + ), + 'jquery.effects.transfer' => array( 'scripts' => 'resources/jquery.effects/jquery.effects.transfer.js', 'dependencies' => 'jquery.effects.core', - ) ), + ), /* MediaWiki */ - 'mediawiki' => new ResourceLoaderFileModule( array( + 'mediawiki' => array( 'scripts' => 'resources/mediawiki/mediawiki.js', 'debugScripts' => 'resources/mediawiki/mediawiki.log.js', 'debugRaw' => false - ) ), - 'mediawiki.util' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.util' => array( 'scripts' => 'resources/mediawiki.util/mediawiki.util.js', 'dependencies' => array( 'jquery.checkboxShiftClick', 'jquery.client' ), 'debugScripts' => 'resources/mediawiki.util/mediawiki.util.test.js', - ) ), - 'mediawiki.action.view.rightClickEdit' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.action.view.rightClickEdit' => array( 'scripts' => 'resources/mediawiki.action/mediawiki.action.view.rightClickEdit.js', - ) ), - 'mediawiki.special.preferences' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.special.preferences' => array( 'scripts' => 'resources/mediawiki.special/mediawiki.special.preferences.js', 'styles' => 'resources/mediawiki.special/mediawiki.special.preferences.css', - ) ), - 'mediawiki.special.search' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.special.search' => array( 'scripts' => 'resources/mediawiki.special/mediawiki.special.search.js', - ) ), - 'mediawiki.action.history' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.action.history' => array( 'scripts' => 'resources/mediawiki.action/mediawiki.action.history.js', 'dependencies' => 'mediawiki.legacy.history', - ) ), - 'mediawiki.language' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.language' => array( 'scripts' => 'resources/mediawiki.language/mediawiki.language.js', 'languageScripts' => array( 'am' => 'resources/mediawiki.language/languages/am.js', @@ -397,111 +393,111 @@ return array( 'uk' => 'resources/mediawiki.language/languages/uk.js', 'wa' => 'resources/mediawiki.language/languages/wa.js', ), - ) ), + ), /* mediawiki Legacy */ - 'mediawiki.legacy.ajax' => new ResourceLoaderFileModule( array( + 'mediawiki.legacy.ajax' => array( 'scripts' => 'skins/common/ajax.js', 'messages' => array( 'watch', 'unwatch', 'watching', 'unwatching', 'tooltip-ca-watch', 'tooltip-ca-unwatch' ), 'dependencies' => 'mediawiki.legacy.wikibits', - ) ), - 'mediawiki.legacy.ajaxwatch' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.ajaxwatch' => array( 'scripts' => 'skins/common/ajaxwatch.js', 'dependencies' => 'mediawiki.legacy.wikibits', - ) ), - 'mediawiki.legacy.block' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.block' => array( 'scripts' => 'skins/common/block.js', 'dependencies' => 'mediawiki.legacy.wikibits', - ) ), - 'mediawiki.legacy.changepassword' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.changepassword' => array( 'scripts' => 'skins/common/changepassword.js', 'dependencies' => 'mediawiki.legacy.wikibits', - ) ), - 'mediawiki.legacy.commonPrint' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.commonPrint' => array( 'styles' => array( 'skins/common/commonPrint.css' => array( 'media' => 'print' ) ), - ) ), - 'mediawiki.legacy.config' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.config' => array( 'scripts' => 'skins/common/config.js', 'styles' => array( 'skins/common/config.css', 'skins/common/config-cc.css' ), 'dependencies' => 'mediawiki.legacy.wikibits', - ) ), - 'mediawiki.legacy.diff' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.diff' => array( 'scripts' => 'skins/common/diff.js', 'styles' => 'skins/common/diff.css', 'dependencies' => 'mediawiki.legacy.wikibits', - ) ), - 'mediawiki.legacy.edit' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.edit' => array( 'scripts' => 'skins/common/edit.js', 'dependencies' => 'mediawiki.legacy.wikibits', - ) ), - 'mediawiki.legacy.enhancedchanges' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.enhancedchanges' => array( 'scripts' => 'skins/common/enhancedchanges.js', 'dependencies' => 'mediawiki.legacy.wikibits', - ) ), - 'mediawiki.legacy.history' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.history' => array( 'scripts' => 'skins/common/history.js', 'dependencies' => 'mediawiki.legacy.wikibits', - ) ), - 'mediawiki.legacy.htmlform' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.htmlform' => array( 'scripts' => 'skins/common/htmlform.js', 'dependencies' => 'mediawiki.legacy.wikibits', - ) ), - 'mediawiki.legacy.IEFixes' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.IEFixes' => array( 'scripts' => 'skins/common/IEFixes.js', 'dependencies' => 'mediawiki.legacy.wikibits', - ) ), - 'mediawiki.legacy.metadata' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.metadata' => array( 'scripts' => 'skins/common/metadata.js', 'dependencies' => 'mediawiki.legacy.wikibits', 'messages' => array( 'metadata-expand', 'metadata-collapse' ), - ) ), - 'mediawiki.legacy.mwsuggest' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.mwsuggest' => array( 'scripts' => 'skins/common/mwsuggest.js', 'dependencies' => 'mediawiki.legacy.wikibits', 'messages' => array( 'search-mwsuggest-enabled', 'search-mwsuggest-disabled' ), - ) ), - 'mediawiki.legacy.password' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.password' => array( 'scripts' => 'skins/common/password.js', 'styles' => 'skins/common/password.css', 'dependencies' => 'mediawiki.legacy.wikibits', - ) ), - 'mediawiki.legacy.prefs' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.prefs' => array( 'scripts' => 'skins/common/prefs.js', 'dependencies' => array( 'mediawiki.legacy.wikibits', 'mediawiki.legacy.htmlform' ), - ) ), - 'mediawiki.legacy.preview' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.preview' => array( 'scripts' => 'skins/common/preview.js', 'dependencies' => 'mediawiki.legacy.wikibits', - ) ), - 'mediawiki.legacy.protect' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.protect' => array( 'scripts' => 'skins/common/protect.js', 'dependencies' => 'mediawiki.legacy.wikibits', - ) ), - 'mediawiki.legacy.search' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.search' => array( 'scripts' => 'skins/common/search.js', 'styles' => 'skins/common/search.css', 'dependencies' => 'mediawiki.legacy.wikibits', - ) ), - 'mediawiki.legacy.shared' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.shared' => array( 'styles' => array( 'skins/common/shared.css' => array( 'media' => 'screen' ) ), - ) ), - 'mediawiki.legacy.oldshared' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.oldshared' => array( 'styles' => array( 'skins/common/oldshared.css' => array( 'media' => 'screen' ) ), - ) ), - 'mediawiki.legacy.upload' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.upload' => array( 'scripts' => 'skins/common/upload.js', 'dependencies' => 'mediawiki.legacy.wikibits', - ) ), - 'mediawiki.legacy.wikibits' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.wikibits' => array( 'scripts' => 'skins/common/wikibits.js', 'dependencies' => 'mediawiki.language', 'messages' => array( 'showtoc', 'hidetoc' ), - ) ), - 'mediawiki.legacy.wikiprintable' => new ResourceLoaderFileModule( array( + ), + 'mediawiki.legacy.wikiprintable' => array( 'styles' => array( 'skins/common/wikiprintable.css' => array( 'media' => 'print' ) ), - ) ), + ), ); -- 2.20.1