wiki.techinc.nl/includes/resourceloader/ResourceLoaderStartUpModule.php

282 lines
9.4 KiB
PHP
Raw Normal View History

<?php
/**
* Module for resource loader initialization.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
* @author Trevor Parscal
* @author Roan Kattouw
*/
class ResourceLoaderStartUpModule extends ResourceLoaderModule {
/* Protected Members */
protected $modifiedTime = array();
/* Protected Methods */
/**
* @param $context ResourceLoaderContext
* @return array
*/
protected function getConfig( $context ) {
global $wgLoadScript, $wgScript, $wgStylePath, $wgScriptExtension,
$wgArticlePath, $wgScriptPath, $wgServer, $wgContLang,
(bug 40448) Replace legacy mwsuggest with mediawiki.searchSuggest The module has been broken for a while now, but nobody noticed because in plain core it is disabled by default, and in the bundle we ship with Extension:Vector (and its SimpleSearch). This commit removed the mediawiki.legacy.mwsuggest module (and related components that become obsolete with its deletion) and replaces it with the new mediawiki.searchSuggest module, which is based on SimpleSearch from Extension:Vector (where it will be removed soon). The following and all references to it in core have been removed, I also made sure that they weren't used in any of extensions/*. Only matches in extensions/Settings and some file that dumped the startup module, and in extensions/Vector which are addressed in I1d5bf81a8a0266c51c99d41eefacc0f4b3ae4b76. Had to make a few updates to jquery.suggestions to make it work in other skins. So far it was only used in Vector, but now that it is used in mediawiki.searchSuggest, I noticed several issues in other skins. Most importantly the fact that it assumed the default offset was from the right corner, which isn't the case in Monobook where the search bar is on the left (in the sidebar). It now detects the appropiate origin corner automatically, and also takes directionality of the page into account. It also uses the correct font-size automatically. Previously it used font-size: 0.8; but that only works in Vector. Every skin seems to have its own way of making a sane font-size. In Monobook the <body> has an extra small font-size which is then fixed in div#globalWrapper, and in Vector it is extra large, which is then fixed as well deeper in the document. Either way, the size on <body> can't be used, and since this suggestions box is appended to the <body> (it is a generic jQuery plugin without knowledge of the document, and even if we could give it knowledge inside the configuration, it'd have to be per-skin). So I removed the Vector specific font-size and let it handle it automatically. This was needed because it is now used in all skins. Removed modules: * mediawiki.legacy.mwsuggest: > Replaced with mediawiki.searchSuggest. Removed messages: * search-mwsuggest-enabled * search-mwsuggest-disabled > No longer used. Removed mw.config.values: * wgMWSuggestTemplate > Obsolete. * wgSearchNamespaces > Obsolete. Removed server-side settings: * $wgEnableMWSuggest > Suggestions are now enabled by default and can be disabled through the user preference `disablesuggest` still. They can be disabled by default site-wide or hidden from prefs through the standard mechanisms for that. * $wgMWSuggestTemplate > Obsolete. Removed methods * SearchEngine::getMWSuggestTemplate() > Obsolete. Filters: $ ack mwsuggest -i -Q --ignore-dir=languages/messages $ ack wgSearchNamespaces -Q Message changes: * vector-simplesearch-preference > It was wrong, it didn't activate search suggestions, that was handled by the Vector extension. This preference in MediaWiki core controls whether the SimpleSearch bar HTML and CSS will be used (e.g. the rectangle search box with the magnifying class instead of the browser-default input field with the plain submit buttons). * searchsuggest-search * searchsuggest-containing These come from Extension:Vector message and should be imported by translatewiki: - vector-simplesearch-search - vector-simplesearch-containing Change-Id: Icd721011b40bb8d2c20aefa8b359a3e45413a07f
2012-09-23 01:06:53 +00:00
$wgVariantArticlePath, $wgActionPaths, $wgVersion,
$wgEnableAPI, $wgEnableWriteAPI, $wgDBname,
$wgSitename, $wgFileExtensions, $wgExtensionAssetsPath,
$wgCookiePrefix, $wgResourceLoaderMaxQueryLength;
$mainPage = Title::newMainPage();
/**
* Namespace related preparation
* - wgNamespaceIds: Key-value pairs of all localized, canonical and aliases for namespaces.
* - wgCaseSensitiveNamespaces: Array of namespaces that are case-sensitive.
*/
$namespaceIds = $wgContLang->getNamespaceIds();
$caseSensitiveNamespaces = array();
foreach( MWNamespace::getCanonicalNamespaces() as $index => $name ) {
2011-06-14 22:51:47 +00:00
$namespaceIds[$wgContLang->lc( $name )] = $index;
if ( !MWNamespace::isCapitalized( $index ) ) {
$caseSensitiveNamespaces[] = $index;
}
}
// Build list of variables
$vars = array(
'wgLoadScript' => $wgLoadScript,
'debug' => $context->getDebug(),
'skin' => $context->getSkin(),
'stylepath' => $wgStylePath,
'wgUrlProtocols' => wfUrlProtocols(),
'wgArticlePath' => $wgArticlePath,
'wgScriptPath' => $wgScriptPath,
'wgScriptExtension' => $wgScriptExtension,
'wgScript' => $wgScript,
'wgVariantArticlePath' => $wgVariantArticlePath,
// Force object to avoid "empty" associative array from
// becoming [] instead of {} in JS (bug 34604)
'wgActionPaths' => (object)$wgActionPaths,
'wgServer' => $wgServer,
'wgUserLanguage' => $context->getLanguage(),
'wgContentLanguage' => $wgContLang->getCode(),
'wgVersion' => $wgVersion,
'wgEnableAPI' => $wgEnableAPI,
'wgEnableWriteAPI' => $wgEnableWriteAPI,
'wgMainPageTitle' => $mainPage->getPrefixedText(),
'wgFormattedNamespaces' => $wgContLang->getFormattedNamespaces(),
'wgNamespaceIds' => $namespaceIds,
'wgSiteName' => $wgSitename,
'wgFileExtensions' => array_values( $wgFileExtensions ),
'wgDBname' => $wgDBname,
// This sucks, it is only needed on Special:Upload, but I could
// not find a way to add vars only for a certain module
'wgFileCanRotate' => BitmapHandler::canRotate(),
'wgAvailableSkins' => Skin::getSkinNames(),
2011-02-16 14:28:26 +00:00
'wgExtensionAssetsPath' => $wgExtensionAssetsPath,
// MediaWiki sets cookies to have this prefix by default
'wgCookiePrefix' => $wgCookiePrefix,
'wgResourceLoaderMaxQueryLength' => $wgResourceLoaderMaxQueryLength,
'wgCaseSensitiveNamespaces' => $caseSensitiveNamespaces,
);
wfRunHooks( 'ResourceLoaderGetConfigVars', array( &$vars ) );
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 ) {
global $wgCacheEpoch;
wfProfileIn( __METHOD__ );
$out = '';
$registrations = array();
* 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.
2010-11-19 10:41:06 +00:00
$resourceLoader = $context->getResourceLoader();
$target = $context->getRequest()->getVal( 'target', 'desktop' );
[ResourceLoader 2]: Add support for multiple loadScript sources Front-end: * New mw.loader method: addSource(). Call with two arguments or an object as first argument for multiple registrations * New property in module registry: "source". Optional for local modules (falls back to 'local'). When loading/using one or more modules, the worker will group the request by source and make separate requests to the sources as needed. * Re-arranging object properties in mw.loader.register to match the same order all other code parts use. * Adding documentation for 'source' and where missing updating it to include 'group' as well. * Refactor of mw.loader.work() by Roan Kattouw and Timo Tijhof:' -- Additional splitting layer by source (in addition to splitting by group), renamed 'groups' to 'splits' -- Clean up of the loop, and removing a no longer needed loop after the for-in-loop -- Much more function documentation in mw.loader.work() -- Moved caching of wgResourceLoaderMaxQueryLength out of the loop and renamed 'limit' to 'maxQueryLength Back-end changed provided through patch by Roan Kattouw (to avoid broken code between commits): * New method in ResourceLoader: addSource(). During construction of ResourceLoader this will be called by default for 'local' with loadScript property set to $wgLoadScript. Additional sources can be registered through $wgResourceLoaderSources (empty array by default) * Calling mw.loader.addSource from the startup module * Passing source to mw.loader.register from startup module * Some new static helper methods Use: * By default nothing should change in core, all modules simply default to 'local'. This info originates from the getSource()-method of the ResourceLoaderModule class, which is inherited to all core ResourceLoaderModule-implementations (none override it) * Third-party users and/or extensions can create new classes extending ResourceLoaderModule, re-implementing the getSource-method to return something else. Basic example: $wgResourceLoaderSources['mywiki'] = array( 'loadScript' => 'http://example.org/w/load.php' ); class MyCentralWikiModule extends ResourceLoaderModule { function getSource(){ return 'mywiki'; } } $wgResourceModules['cool.stuff'] => array( 'class' => 'MyCentralWikiModule' ); More complicated example // imagine some stuff with a ForeignGadgetRepo class, putting stuff in $wgResourceLoaderSources in the __construct() method class ForeignGadgetRepoGadget extends ResourceLoaderModule { function getSource(){ return $this->source; } } Loading: Loading is completely transparent, stuff like $wgOut->addModules() or mw.loader.loader/using both take it as any other module and load from the right source accordingly. -- This commit is part of the ResourceLoader 2 project.
2011-07-26 21:10:34 +00:00
// Register sources
$out .= ResourceLoader::makeLoaderSourcesScript( $resourceLoader->getSources() );
// Register modules
* 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.
2010-11-19 10:41:06 +00:00
foreach ( $resourceLoader->getModuleNames() as $name ) {
$module = $resourceLoader->getModule( $name );
$moduleTargets = $module->getTargets();
if ( !in_array( $target, $moduleTargets ) ) {
continue;
}
$deps = $module->getDependencies();
$group = $module->getGroup();
$source = $module->getSource();
// Support module loader scripts
$loader = $module->getLoaderScript();
if ( $loader !== false ) {
$version = wfTimestamp( TS_ISO_8601_BASIC,
$module->getModifiedTime( $context ) );
$out .= ResourceLoader::makeCustomLoaderScript( $name, $version, $deps, $group, $source, $loader );
continue;
}
// Automatically register module
// getModifiedTime() is supposed to return a UNIX timestamp, but it doesn't always
// seem to do that, and custom implementations might forget. Coerce it to TS_UNIX
$moduleMtime = wfTimestamp( TS_UNIX, $module->getModifiedTime( $context ) );
$mtime = max( $moduleMtime, wfTimestamp( TS_UNIX, $wgCacheEpoch ) );
// Modules without dependencies, a group or a foreign source pass two arguments (name, timestamp) to
// mw.loader.register()
if ( !count( $deps ) && $group === null && $source === 'local' ) {
$registrations[] = array( $name, $mtime );
}
// Modules with dependencies but no group or foreign source pass three arguments
// (name, timestamp, dependencies) to mw.loader.register()
elseif ( $group === null && $source === 'local' ) {
$registrations[] = array( $name, $mtime, $deps );
}
// Modules with a group but no foreign source pass four arguments (name, timestamp, dependencies, group)
// to mw.loader.register()
elseif ( $source === 'local' ) {
$registrations[] = array( $name, $mtime, $deps, $group );
}
// Modules with a foreign source pass five arguments (name, timestamp, dependencies, group, source)
// to mw.loader.register()
else {
$registrations[] = array( $name, $mtime, $deps, $group, $source );
}
}
$out .= ResourceLoader::makeLoaderRegisterScript( $registrations );
wfProfileOut( __METHOD__ );
return $out;
}
/* Methods */
/**
* @return bool
*/
public function isRaw() {
return true;
}
/**
* @param $context ResourceLoaderContext
* @return string
*/
public function getScript( ResourceLoaderContext $context ) {
global $IP, $wgLoadScript, $wgLegacyJavaScriptGlobals;
$out = file_get_contents( "$IP/resources/startup.js" );
if ( $context->getOnly() === 'scripts' ) {
// The core modules:
$moduleNames = array( 'jquery', 'mediawiki' );
wfRunHooks( 'ResourceLoaderGetStartupModules', array( &$moduleNames ) );
// Get the latest version
$loader = $context->getResourceLoader();
$version = 0;
foreach ( $moduleNames as $moduleName ) {
$version = max( $version,
$loader->getModule( $moduleName )->getModifiedTime( $context )
);
}
// Build load query for StartupModules
$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 )
);
// Ensure uniform query order
ksort( $query );
// Startup function
$configuration = $this->getConfig( $context );
$registrations = self::getModuleRegistrations( $context );
$registrations = str_replace( "\n", "\n\t", trim( $registrations ) ); // fix indentation
$out .= "var startUp = function() {\n" .
"\tmw.config = new " . Xml::encodeJsCall( 'mw.Map', array( $wgLegacyJavaScriptGlobals ) ) . "\n" .
"\t$registrations\n" .
"\t" . Xml::encodeJsCall( 'mw.config.set', array( $configuration ) ) .
"};\n";
// Conditional script injection
$scriptTag = Html::linkedScript( $wgLoadScript . '?' . wfArrayToCgi( $query ) );
$out .= "if ( isCompatible() ) {\n" .
"\t" . Xml::encodeJsCall( 'document.write', array( $scriptTag ) ) .
"}\n" .
"delete isCompatible;";
}
return $out;
}
/**
* @return bool
*/
Fix the fixme on r88053: dependency handling was broken in debug mode in certain cases. More specifically, if A is a file module that depends on B, B is a wiki module that depends on C and C is a file module, the loading order is CBA (correct) in production mode but was BCA (wrong) in debug mode. Fixed this by URL-ifying scripts and styles for those modules in debug mode, as I said to on CR. What this means is that the initial debug=true request for a module will now always return arrays of URLs, never the JS or CSS itself. This was already the case for file modules (which returned arrays of URLs to the raw files), but not for other modules (which returned the JS and CSS itself). So for non-file modules, load.php?modules=foo&debug=true now returns some JS that instructs the loader to fetch the module's JS from load.php?modules=foo&debug=true&only=scripts and the CSS from ...&only=styles . * Removed the magic behavior where ResourceLoaderModule::getScripts() and getStyles() could return an array of URLs where the documentation said they should return a JS/CSS string. Because I didn't restructure the calling code too much, the old magical behavior should still work. * Instead, move this behavior to getScriptURLsForDebug() and getStyleURLsForDebug(). The default implementation constructs a single URL for a load.php request for the module with debug=true&only=scripts (or styles). The URL building code duplicates some things from OutputPage::makeResourceLoaderLink(), I'll clean that up later. ResourceLoaderFileModule overrides this method to return URLs to the raw files, using code that I removed from getScripts()/getStyles() * Add ResourceLoaderModule::supportsURLLoading(), which returns true by default but may return false to indicate that a module does not support loading via a URL. This is needed to respect $this->debugRaw in ResourceLoaderFileModule (set to true for jquery and mediawiki), and obviously for the startup module as well, because we get bootstrapping problems otherwise (can't call mw.loader.implement() when the code for mw.loader isn't loaded yet)
2011-09-13 17:13:53 +00:00
public function supportsURLLoading() {
return false;
}
/**
* @param $context ResourceLoaderContext
* @return array|mixed
*/
public function getModifiedTime( ResourceLoaderContext $context ) {
global $IP, $wgCacheEpoch;
$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 );
$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!
$time = wfTimestamp( TS_UNIX, $wgCacheEpoch );
* 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.
2010-11-19 10:41:06 +00:00
foreach ( $loader->getModuleNames() as $name ) {
$module = $loader->getModule( $name );
$time = max( $time, $module->getModifiedTime( $context ) );
}
return $this->modifiedTime[$hash] = $time;
}
/* Methods */
/**
* @return string
*/
public function getGroup() {
return 'startup';
}
}