MediaWiki  REL1_22
ResourceLoaderStartUpModule.php
Go to the documentation of this file.
00001 <?php
00025 class ResourceLoaderStartUpModule extends ResourceLoaderModule {
00026 
00027     /* Protected Members */
00028 
00029     protected $modifiedTime = array();
00030     protected $targets = array( 'desktop', 'mobile' );
00031 
00032     /* Protected Methods */
00033 
00038     protected function getConfig( $context ) {
00039         global $wgLoadScript, $wgScript, $wgStylePath, $wgScriptExtension,
00040             $wgArticlePath, $wgScriptPath, $wgServer, $wgContLang,
00041             $wgVariantArticlePath, $wgActionPaths, $wgVersion,
00042             $wgEnableAPI, $wgEnableWriteAPI, $wgDBname,
00043             $wgSitename, $wgFileExtensions, $wgExtensionAssetsPath,
00044             $wgCookiePrefix, $wgResourceLoaderMaxQueryLength;
00045 
00046         $mainPage = Title::newMainPage();
00047 
00053         $namespaceIds = $wgContLang->getNamespaceIds();
00054         $caseSensitiveNamespaces = array();
00055         foreach ( MWNamespace::getCanonicalNamespaces() as $index => $name ) {
00056             $namespaceIds[$wgContLang->lc( $name )] = $index;
00057             if ( !MWNamespace::isCapitalized( $index ) ) {
00058                 $caseSensitiveNamespaces[] = $index;
00059             }
00060         }
00061 
00062         // Build list of variables
00063         $vars = array(
00064             'wgLoadScript' => $wgLoadScript,
00065             'debug' => $context->getDebug(),
00066             'skin' => $context->getSkin(),
00067             'stylepath' => $wgStylePath,
00068             'wgUrlProtocols' => wfUrlProtocols(),
00069             'wgArticlePath' => $wgArticlePath,
00070             'wgScriptPath' => $wgScriptPath,
00071             'wgScriptExtension' => $wgScriptExtension,
00072             'wgScript' => $wgScript,
00073             'wgVariantArticlePath' => $wgVariantArticlePath,
00074             // Force object to avoid "empty" associative array from
00075             // becoming [] instead of {} in JS (bug 34604)
00076             'wgActionPaths' => (object)$wgActionPaths,
00077             'wgServer' => $wgServer,
00078             'wgUserLanguage' => $context->getLanguage(),
00079             'wgContentLanguage' => $wgContLang->getCode(),
00080             'wgVersion' => $wgVersion,
00081             'wgEnableAPI' => $wgEnableAPI,
00082             'wgEnableWriteAPI' => $wgEnableWriteAPI,
00083             'wgMainPageTitle' => $mainPage->getPrefixedText(),
00084             'wgFormattedNamespaces' => $wgContLang->getFormattedNamespaces(),
00085             'wgNamespaceIds' => $namespaceIds,
00086             'wgSiteName' => $wgSitename,
00087             'wgFileExtensions' => array_values( array_unique( $wgFileExtensions ) ),
00088             'wgDBname' => $wgDBname,
00089             // This sucks, it is only needed on Special:Upload, but I could
00090             // not find a way to add vars only for a certain module
00091             'wgFileCanRotate' => BitmapHandler::canRotate(),
00092             'wgAvailableSkins' => Skin::getSkinNames(),
00093             'wgExtensionAssetsPath' => $wgExtensionAssetsPath,
00094             // MediaWiki sets cookies to have this prefix by default
00095             'wgCookiePrefix' => $wgCookiePrefix,
00096             'wgResourceLoaderMaxQueryLength' => $wgResourceLoaderMaxQueryLength,
00097             'wgCaseSensitiveNamespaces' => $caseSensitiveNamespaces,
00098             'wgLegalTitleChars' => Title::convertByteClassToUnicodeClass( Title::legalChars() ),
00099         );
00100 
00101         wfRunHooks( 'ResourceLoaderGetConfigVars', array( &$vars ) );
00102 
00103         return $vars;
00104     }
00105 
00112     public static function getModuleRegistrations( ResourceLoaderContext $context ) {
00113         global $wgCacheEpoch;
00114         wfProfileIn( __METHOD__ );
00115 
00116         $out = '';
00117         $registrations = array();
00118         $resourceLoader = $context->getResourceLoader();
00119         $target = $context->getRequest()->getVal( 'target', 'desktop' );
00120 
00121         // Register sources
00122         $out .= ResourceLoader::makeLoaderSourcesScript( $resourceLoader->getSources() );
00123 
00124         // Register modules
00125         foreach ( $resourceLoader->getModuleNames() as $name ) {
00126             $module = $resourceLoader->getModule( $name );
00127             $moduleTargets = $module->getTargets();
00128             if ( !in_array( $target, $moduleTargets ) ) {
00129                 continue;
00130             }
00131             $deps = $module->getDependencies();
00132             $group = $module->getGroup();
00133             $source = $module->getSource();
00134             // Support module loader scripts
00135             $loader = $module->getLoaderScript();
00136             if ( $loader !== false ) {
00137                 $version = wfTimestamp( TS_ISO_8601_BASIC,
00138                     $module->getModifiedTime( $context ) );
00139                 $out .= ResourceLoader::makeCustomLoaderScript( $name, $version, $deps, $group, $source, $loader );
00140                 continue;
00141             }
00142 
00143             // Automatically register module
00144             // getModifiedTime() is supposed to return a UNIX timestamp, but it doesn't always
00145             // seem to do that, and custom implementations might forget. Coerce it to TS_UNIX
00146             $moduleMtime = wfTimestamp( TS_UNIX, $module->getModifiedTime( $context ) );
00147             $mtime = max( $moduleMtime, wfTimestamp( TS_UNIX, $wgCacheEpoch ) );
00148             // Modules without dependencies, a group or a foreign source pass two arguments (name, timestamp) to
00149             // mw.loader.register()
00150             if ( !count( $deps ) && $group === null && $source === 'local' ) {
00151                 $registrations[] = array( $name, $mtime );
00152             }
00153             // Modules with dependencies but no group or foreign source pass three arguments
00154             // (name, timestamp, dependencies) to mw.loader.register()
00155             elseif ( $group === null && $source === 'local' ) {
00156                 $registrations[] = array( $name, $mtime, $deps );
00157             }
00158             // Modules with a group but no foreign source pass four arguments (name, timestamp, dependencies, group)
00159             // to mw.loader.register()
00160             elseif ( $source === 'local' ) {
00161                 $registrations[] = array( $name, $mtime, $deps, $group );
00162             }
00163             // Modules with a foreign source pass five arguments (name, timestamp, dependencies, group, source)
00164             // to mw.loader.register()
00165             else {
00166                 $registrations[] = array( $name, $mtime, $deps, $group, $source );
00167             }
00168         }
00169         $out .= ResourceLoader::makeLoaderRegisterScript( $registrations );
00170 
00171         wfProfileOut( __METHOD__ );
00172         return $out;
00173     }
00174 
00175     /* Methods */
00176 
00180     public function isRaw() {
00181         return true;
00182     }
00183 
00188     public function getScript( ResourceLoaderContext $context ) {
00189         global $IP, $wgLegacyJavaScriptGlobals;
00190 
00191         $out = file_get_contents( "$IP/resources/startup.js" );
00192         if ( $context->getOnly() === 'scripts' ) {
00193 
00194             // The core modules:
00195             $moduleNames = array( 'jquery', 'mediawiki' );
00196             wfRunHooks( 'ResourceLoaderGetStartupModules', array( &$moduleNames ) );
00197 
00198             // Get the latest version
00199             $loader = $context->getResourceLoader();
00200             $version = 0;
00201             foreach ( $moduleNames as $moduleName ) {
00202                 $version = max( $version,
00203                     $loader->getModule( $moduleName )->getModifiedTime( $context )
00204                 );
00205             }
00206             // Build load query for StartupModules
00207             $query = array(
00208                 'modules' => ResourceLoader::makePackedModulesString( $moduleNames ),
00209                 'only' => 'scripts',
00210                 'lang' => $context->getLanguage(),
00211                 'skin' => $context->getSkin(),
00212                 'debug' => $context->getDebug() ? 'true' : 'false',
00213                 'version' => wfTimestamp( TS_ISO_8601_BASIC, $version )
00214             );
00215             // Ensure uniform query order
00216             ksort( $query );
00217 
00218             // Startup function
00219             $configuration = $this->getConfig( $context );
00220             $registrations = self::getModuleRegistrations( $context );
00221             $registrations = str_replace( "\n", "\n\t", trim( $registrations ) ); // fix indentation
00222             $out .= "var startUp = function() {\n" .
00223                 "\tmw.config = new " . Xml::encodeJsCall( 'mw.Map', array( $wgLegacyJavaScriptGlobals ) ) . "\n" .
00224                 "\t$registrations\n" .
00225                 "\t" . Xml::encodeJsCall( 'mw.config.set', array( $configuration ) ) .
00226                 "};\n";
00227 
00228             // Conditional script injection
00229             $scriptTag = Html::linkedScript( wfAppendQuery( wfScript( 'load' ), $query ) );
00230             $out .= "if ( isCompatible() ) {\n" .
00231                 "\t" . Xml::encodeJsCall( 'document.write', array( $scriptTag ) ) .
00232                 "}\n" .
00233                 "delete isCompatible;";
00234         }
00235 
00236         return $out;
00237     }
00238 
00242     public function supportsURLLoading() {
00243         return false;
00244     }
00245 
00250     public function getModifiedTime( ResourceLoaderContext $context ) {
00251         global $IP, $wgCacheEpoch;
00252 
00253         $hash = $context->getHash();
00254         if ( isset( $this->modifiedTime[$hash] ) ) {
00255             return $this->modifiedTime[$hash];
00256         }
00257 
00258         // Call preloadModuleInfo() on ALL modules as we're about
00259         // to call getModifiedTime() on all of them
00260         $loader = $context->getResourceLoader();
00261         $loader->preloadModuleInfo( $loader->getModuleNames(), $context );
00262 
00263         $this->modifiedTime[$hash] = filemtime( "$IP/resources/startup.js" );
00264         // ATTENTION!: Because of the line above, this is not going to cause
00265         // infinite recursion - think carefully before making changes to this
00266         // code!
00267         $time = wfTimestamp( TS_UNIX, $wgCacheEpoch );
00268         foreach ( $loader->getModuleNames() as $name ) {
00269             $module = $loader->getModule( $name );
00270             $time = max( $time, $module->getModifiedTime( $context ) );
00271         }
00272         return $this->modifiedTime[$hash] = $time;
00273     }
00274 
00275     /* Methods */
00276 
00280     public function getGroup() {
00281         return 'startup';
00282     }
00283 }