public function getOnly() { if ($this->only === self::INHERIT_VALUE) { return $this->context->getOnly(); } return $this->only; }
public function getOnly() { if (!is_null($this->only)) { return $this->only; } else { return $this->context->getOnly(); } }
public function testTypicalRequest() { $ctx = new ResourceLoaderContext($this->getResourceLoader(), new FauxRequest(['debug' => 'false', 'lang' => 'zh', 'modules' => 'foo|foo.quux,baz,bar|baz.quux', 'only' => 'styles', 'skin' => 'fallback'])); // Request parameters $this->assertEquals($ctx->getModules(), ['foo', 'foo.quux', 'foo.baz', 'foo.bar', 'baz.quux']); $this->assertEquals(false, $ctx->getDebug()); $this->assertEquals('zh', $ctx->getLanguage()); $this->assertEquals('styles', $ctx->getOnly()); $this->assertEquals('fallback', $ctx->getSkin()); $this->assertEquals(null, $ctx->getUser()); // Misc $this->assertEquals('ltr', $ctx->getDirection()); $this->assertEquals('zh|fallback|||styles|||||', $ctx->getHash()); }
/** * Construct an ResourceFileCache from a context * @param $context ResourceLoaderContext * @return ResourceFileCache */ public static function newFromContext(ResourceLoaderContext $context) { $cache = new self(); if ($context->getOnly() === 'styles') { $cache->mType = 'css'; } else { $cache->mType = 'js'; } $modules = array_unique($context->getModules()); // remove duplicates sort($modules); // normalize the order (permutation => combination) $cache->mKey = sha1($context->getHash() . implode('|', $modules)); if (count($modules) == 1) { $cache->mCacheWorthy = true; // won't take up much space } return $cache; }
/** * @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: $modules = array('jquery', 'mediawiki'); wfRunHooks('ResourceLoaderGetStartupModules', array(&$modules)); // Get the latest version $version = 0; foreach ($modules as $moduleName) { $version = max($version, $context->getResourceLoader()->getModule($moduleName)->getModifiedTime($context)); } // Build load query for StartupModules $query = array('modules' => ResourceLoader::makePackedModulesString($modules), '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); $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)) . "\t" . Xml::encodeJsCall('mw.loader.state', array(array('jquery' => 'ready'))) . "};\n"; // Conditional script injection // Wikia change - begin - @author: wladek // $scriptTag = Html::linkedScript( $wgLoadScript . '?' . wfArrayToCGI( $query ) ); // get jquery from CDN if we have wsl and getJqueryUrl loaded $scriptTagJquery = Xml::encodeJsVar(Html::linkedScript(ResourceLoader::makeLoaderURL($modules, $query['lang'], $query['skin'], null, $query['version'], $context->getDebug(), 'scripts'))); $scriptTagNoJquery = Xml::encodeJsVar(Html::linkedScript(ResourceLoader::makeLoaderURL(array('mediawiki'), $query['lang'], $query['skin'], null, $query['version'], $context->getDebug(), 'scripts'))); $scriptTag = <<<ENDSCRIPT ( (window.wsl && window.getJqueryUrl && window.wgJqueryUrl) ? (wsl.buildScript(window.getJqueryUrl()) + {$scriptTagNoJquery}) : ({$scriptTagJquery}) ) ENDSCRIPT; $scriptTag = new XmlJsCode($scriptTag); // Wikia change - end $out .= "if ( isCompatible() ) {\n" . "\t" . Xml::encodeJsCall('document.write', array($scriptTag)) . "}\n" . "delete isCompatible;"; } return $out; }
/** * Helper for createLoaderURL() * * @since 1.24 * @see makeLoaderQuery * @param ResourceLoaderContext $context * @param array $extraQuery * @return array */ public static function createLoaderQuery(ResourceLoaderContext $context, $extraQuery = array()) { return self::makeLoaderQuery($context->getModules(), $context->getLanguage(), $context->getSkin(), $context->getUser(), $context->getVersion(), $context->getDebug(), $context->getOnly(), $context->getRequest()->getBool('printable'), $context->getRequest()->getBool('handheld'), $extraQuery); }
/** * Generates code for a response * * @param $context ResourceLoaderContext: Context in which to generate a response * @param $modules Array: List of module objects keyed by module name * @param $missing Array: List of unavailable modules (optional) * @return String: Response data */ public function makeModuleResponse(ResourceLoaderContext $context, array $modules, $missing = array()) { $out = ''; $exceptions = ''; if ($modules === array() && $missing === array()) { return '/* No modules requested. Max made me put this here */'; } wfProfileIn(__METHOD__); // Pre-fetch blobs if ($context->shouldIncludeMessages()) { try { $blobs = MessageBlobStore::get($this, $modules, $context->getLanguage()); } catch (Exception $e) { // Add exception to the output as a comment $exceptions .= $this->makeComment($e->__toString()); } } else { $blobs = array(); } // Generate output $isRaw = false; foreach ($modules as $name => $module) { /** * @var $module ResourceLoaderModule */ wfProfileIn(__METHOD__ . '-' . $name); try { $scripts = ''; if ($context->shouldIncludeScripts()) { // If we are in debug mode, we'll want to return an array of URLs if possible // However, we can't do this if the module doesn't support it // We also can't do this if there is an only= parameter, because we have to give // the module a way to return a load.php URL without causing an infinite loop if ($context->getDebug() && !$context->getOnly() && $module->supportsURLLoading()) { $scripts = $module->getScriptURLsForDebug($context); } else { $scripts = $module->getScript($context); if (is_string($scripts) && strlen($scripts) && substr($scripts, -1) !== ';') { // bug 27054: Append semicolon to prevent weird bugs // caused by files not terminating their statements right $scripts .= ";\n"; } } } // Styles $styles = array(); if ($context->shouldIncludeStyles()) { // Don't create empty stylesheets like array( '' => '' ) for modules // that don't *have* any stylesheets (bug 38024). $stylePairs = $module->getStyles($context); if (count($stylePairs)) { // If we are in debug mode without &only= set, we'll want to return an array of URLs // See comment near shouldIncludeScripts() for more details if ($context->getDebug() && !$context->getOnly() && $module->supportsURLLoading()) { $styles = array('url' => $module->getStyleURLsForDebug($context)); } else { // Minify CSS before embedding in mw.loader.implement call // (unless in debug mode) if (!$context->getDebug()) { foreach ($stylePairs as $media => $style) { // Can be either a string or an array of strings. if (is_array($style)) { $stylePairs[$media] = array(); foreach ($style as $cssText) { if (is_string($cssText)) { $stylePairs[$media][] = $this->filter('minify-css', $cssText); } } } elseif (is_string($style)) { $stylePairs[$media] = $this->filter('minify-css', $style); } } } // Wrap styles into @media groups as needed and flatten into a numerical array $styles = array('css' => self::makeCombinedStyles($stylePairs)); } } } // Messages $messagesBlob = isset($blobs[$name]) ? $blobs[$name] : '{}'; // Append output switch ($context->getOnly()) { case 'scripts': if (is_string($scripts)) { // Load scripts raw... $out .= $scripts; } elseif (is_array($scripts)) { // ...except when $scripts is an array of URLs $out .= self::makeLoaderImplementScript($name, $scripts, array(), array()); } break; case 'styles': // We no longer seperate into media, they are all combined now with // custom media type groups into @media .. {} sections as part of the css string. // Module returns either an empty array or a numerical array with css strings. $out .= isset($styles['css']) ? implode('', $styles['css']) : ''; break; case 'messages': $out .= self::makeMessageSetScript(new XmlJsCode($messagesBlob)); break; default: $out .= self::makeLoaderImplementScript($name, $scripts, $styles, new XmlJsCode($messagesBlob)); break; } } catch (Exception $e) { // Add exception to the output as a comment $exceptions .= $this->makeComment($e->__toString()); // Register module as missing $missing[] = $name; unset($modules[$name]); } $isRaw |= $module->isRaw(); wfProfileOut(__METHOD__ . '-' . $name); } // Update module states if ($context->shouldIncludeScripts() && !$context->getRaw() && !$isRaw) { // Set the state of modules loaded as only scripts to ready if (count($modules) && $context->getOnly() === 'scripts') { $out .= self::makeLoaderStateScript(array_fill_keys(array_keys($modules), 'ready')); } // Set the state of modules which were requested but unavailable as missing if (is_array($missing) && count($missing)) { $out .= self::makeLoaderStateScript(array_fill_keys($missing, 'missing')); } } if (!$context->getDebug()) { if ($context->getOnly() === 'styles') { $out = $this->filter('minify-css', $out); } else { $out = $this->filter('minify-js', $out); } } wfProfileOut(__METHOD__); return $exceptions . $out; }
/** * @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; }
/** * Generates code for a response * * @param $context ResourceLoaderContext: Context in which to generate a response * @param $modules Array: List of module objects keyed by module name * @param $missing Array: List of unavailable modules (optional) * @return String: Response data */ public function makeModuleResponse(ResourceLoaderContext $context, array $modules, $missing = array()) { $out = ''; $exceptions = ''; if ($modules === array() && $missing === array()) { return '/* No modules requested. Max made me put this here */'; } wfProfileIn(__METHOD__); // Pre-fetch blobs if ($context->shouldIncludeMessages()) { try { $blobs = MessageBlobStore::get($this, $modules, $context->getLanguage()); } catch (Exception $e) { // Add exception to the output as a comment $exceptions .= $this->formatException($e); } } else { $blobs = array(); } // Generate output foreach ($modules as $name => $module) { /** * @var $module ResourceLoaderModule */ wfProfileIn(__METHOD__ . '-' . $name); try { $scripts = ''; if ($context->shouldIncludeScripts()) { // If we are in debug mode, we'll want to return an array of URLs if possible // However, we can't do this if the module doesn't support it // We also can't do this if there is an only= parameter, because we have to give // the module a way to return a load.php URL without causing an infinite loop if ($context->getDebug() && !$context->getOnly() && $module->supportsURLLoading()) { $scripts = $module->getScriptURLsForDebug($context); } else { $scripts = $module->getScript($context); if (is_string($scripts)) { // bug 27054: Append semicolon to prevent weird bugs // caused by files not terminating their statements right $scripts .= ";\n"; } } } // Styles $styles = array(); if ($context->shouldIncludeStyles()) { // If we are in debug mode, we'll want to return an array of URLs // See comment near shouldIncludeScripts() for more details if ($context->getDebug() && !$context->getOnly() && $module->supportsURLLoading()) { $styles = $module->getStyleURLsForDebug($context); } else { $styles = $module->getStyles($context); } } // Messages $messagesBlob = isset($blobs[$name]) ? $blobs[$name] : '{}'; // Append output switch ($context->getOnly()) { case 'scripts': if (is_string($scripts)) { // Load scripts raw... $out .= $scripts; } elseif (is_array($scripts)) { // ...except when $scripts is an array of URLs $out .= self::makeLoaderImplementScript($name, $scripts, array(), array()); } break; case 'styles': $out .= self::makeCombinedStyles($styles); break; case 'messages': $out .= self::makeMessageSetScript(new XmlJsCode($messagesBlob)); break; default: // Minify CSS before embedding in mw.loader.implement call // (unless in debug mode) if (!$context->getDebug()) { foreach ($styles as $media => $style) { if (is_string($style)) { $styles[$media] = $this->filter('minify-css', $style); } } } $out .= self::makeLoaderImplementScript($name, $scripts, $styles, new XmlJsCode($messagesBlob)); break; } } catch (Exception $e) { // Add exception to the output as a comment $exceptions .= $this->formatException($e); // Register module as missing $missing[] = $name; unset($modules[$name]); } wfProfileOut(__METHOD__ . '-' . $name); } // Update module states if ($context->shouldIncludeScripts()) { // Set the state of modules loaded as only scripts to ready if (count($modules) && $context->getOnly() === 'scripts' && !isset($modules['startup'])) { $out .= self::makeLoaderStateScript(array_fill_keys(array_keys($modules), 'ready')); } // Set the state of modules which were requested but unavailable as missing if (is_array($missing) && count($missing)) { $out .= self::makeLoaderStateScript(array_fill_keys($missing, 'missing')); } } if (!$context->getDebug()) { if ($context->getOnly() === 'styles') { $out = $this->filter('minify-css', $out); } else { $out = $this->filter('minify-js', $out); } } wfProfileOut(__METHOD__); return $exceptions . $out; }
/** * @param ResourceLoaderContext $context * @return string */ public function getScript(ResourceLoaderContext $context) { global $IP; if ($context->getOnly() !== 'scripts') { return '/* Requires only=script */'; } $out = file_get_contents("{$IP}/resources/src/startup.js"); $pairs = array_map(function ($value) { $value = FormatJson::encode($value, ResourceLoader::inDebugMode(), FormatJson::ALL_OK); // Fix indentation $value = str_replace("\n", "\n\t", $value); return $value; }, ['$VARS.wgLegacyJavaScriptGlobals' => $this->getConfig()->get('LegacyJavaScriptGlobals'), '$VARS.configuration' => $this->getConfigSettings($context), '$VARS.baseModulesUri' => self::getStartupModulesUrl($context)]); $pairs['$CODE.registrations()'] = str_replace("\n", "\n\t", trim($this->getModuleRegistrations($context))); return strtr($out, $pairs); }
/** * @param ResourceLoaderContext $context * @return string */ public function getScript(ResourceLoaderContext $context) { global $IP, $wgLegacyJavaScriptGlobals; $out = file_get_contents("{$IP}/resources/src/startup.js"); if ($context->getOnly() === 'scripts') { // Startup function $configuration = $this->getConfig($context); $registrations = self::getModuleRegistrations($context); // Fix indentation $registrations = str_replace("\n", "\n\t", trim($registrations)); $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(self::getStartupModulesUrl($context)); $out .= "if ( isCompatible() ) {\n" . "\t" . Xml::encodeJsCall('document.write', array($scriptTag)) . "}"; } return $out; }
/** * Bundle all resources attached to this module into an array. * * @since 1.26 * @param ResourceLoaderContext $context * @return array */ protected final function buildContent(ResourceLoaderContext $context) { $rl = $context->getResourceLoader(); $stats = RequestContext::getMain()->getStats(); $statStart = microtime(true); // Only include properties that are relevant to this context (e.g. only=scripts) // and that are non-empty (e.g. don't include "templates" for modules without // templates). This helps prevent invalidating cache for all modules when new // optional properties are introduced. $content = array(); // Scripts if ($context->shouldIncludeScripts()) { // If we are in debug mode, we'll want to return an array of URLs if possible // However, we can't do this if the module doesn't support it // We also can't do this if there is an only= parameter, because we have to give // the module a way to return a load.php URL without causing an infinite loop if ($context->getDebug() && !$context->getOnly() && $this->supportsURLLoading()) { $scripts = $this->getScriptURLsForDebug($context); } else { $scripts = $this->getScript($context); // rtrim() because there are usually a few line breaks // after the last ';'. A new line at EOF, a new line // added by ResourceLoaderFileModule::readScriptFiles, etc. if (is_string($scripts) && strlen($scripts) && substr(rtrim($scripts), -1) !== ';') { // Append semicolon to prevent weird bugs caused by files not // terminating their statements right (bug 27054) $scripts .= ";\n"; } } $content['scripts'] = $scripts; } // Styles if ($context->shouldIncludeStyles()) { $styles = array(); // Don't create empty stylesheets like array( '' => '' ) for modules // that don't *have* any stylesheets (bug 38024). $stylePairs = $this->getStyles($context); if (count($stylePairs)) { // If we are in debug mode without &only= set, we'll want to return an array of URLs // See comment near shouldIncludeScripts() for more details if ($context->getDebug() && !$context->getOnly() && $this->supportsURLLoading()) { $styles = array('url' => $this->getStyleURLsForDebug($context)); } else { // Minify CSS before embedding in mw.loader.implement call // (unless in debug mode) if (!$context->getDebug()) { foreach ($stylePairs as $media => $style) { // Can be either a string or an array of strings. if (is_array($style)) { $stylePairs[$media] = array(); foreach ($style as $cssText) { if (is_string($cssText)) { $stylePairs[$media][] = $rl->filter('minify-css', $cssText); } } } elseif (is_string($style)) { $stylePairs[$media] = $rl->filter('minify-css', $style); } } } // Wrap styles into @media groups as needed and flatten into a numerical array $styles = array('css' => $rl->makeCombinedStyles($stylePairs)); } } $content['styles'] = $styles; } // Messages $blobs = $rl->getMessageBlobStore()->get($rl, array($this->getName() => $this), $context->getLanguage()); if (isset($blobs[$this->getName()])) { $content['messagesBlob'] = $blobs[$this->getName()]; } $templates = $this->getTemplates(); if ($templates) { $content['templates'] = $templates; } $statTiming = microtime(true) - $statStart; $statName = strtr($this->getName(), '.', '_'); $stats->timing("resourceloader_build.all", 1000 * $statTiming); $stats->timing("resourceloader_build.{$statName}", 1000 * $statTiming); return $content; }
/** * @param $context ResourceLoaderContext * @return string */ public function getScript(ResourceLoaderContext $context) { global $IP, $wgScriptPath, $wgLoadScript, $wgLegacyJavaScriptGlobals; $out = file_get_contents("{$IP}/{$wgScriptPath}/resources/startup.js"); if ($context->getOnly() === 'scripts') { // The core modules: $modules = array('jquery', 'mediawiki'); wfRunHooks('ResourceLoaderGetStartupModules', array(&$modules)); // Get the latest version $version = 0; foreach ($modules as $moduleName) { $version = max($version, $context->getResourceLoader()->getModule($moduleName)->getModifiedTime($context)); } // Build load query for StartupModules $query = array('modules' => ResourceLoader::makePackedModulesString($modules), '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); $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"; $fauxRequest = new WebRequest(); $modulesToLoad = array(); $resourceLoader = $context->getResourceLoader(); foreach ($modules as $moduleName) { $modulesToLoad[$moduleName] = $resourceLoader->getModule($moduleName); } $s = $context->getResourceLoader()->makeModuleResponse(new MwEmbedResourceLoaderContext($context->getResourceLoader(), $fauxRequest), $modulesToLoad, array()); $out .= $s; // // Conditional script injection // $out .= "if ( isCompatible() ) {\n" . // "\t" . Xml::encodeJsCall( 'writeScript', array( $wgLoadScript . '?' . wfArrayToCGI( $query ) ) ) . // "}\n" . // "delete isCompatible;"; } return $out; }
/** * Hook handler. * * If mode equals 'articles' in the request, bootstraps fake module and reinitialize * ResourceLoaderContext object to include the just-defined fake module. * * @param $resourceLoader ResourceLoader * @param $context ResourceLoaderContext * @return bool */ public function onResourceLoaderBeforeRespond($resourceLoader, ResourceLoaderContext &$context) { /* @var $request WebRequest */ $request = $context->getRequest(); if ($request->getVal('mode') !== 'articles') { return true; } $only = $context->getOnly(); $type = $this->getTypeByOnly($only); if (empty($type)) { return true; } $articles = $request->getVal('articles'); $articles = explode('|', $articles); if (empty($articles)) { return true; } // prepare fake ResourceLoader module metadata $moduleName = md5(serialize(array($articles, $only, $context->getHash()))); $moduleFullName = 'wikia.fake.articles.' . $moduleName; $moduleInfo = array('class' => 'ResourceLoaderCustomWikiModule', 'articles' => $this->parseArticleNames($articles), 'type' => $type); // register new fake module $resourceLoader->register($moduleFullName, $moduleInfo); // reinitialize ResourceLoader context $request->setVal('modules', $moduleFullName); $context = new ResourceLoaderContext($resourceLoader, $request); return true; }
public function getScript(ResourceLoaderContext $context) { global $IP, $wgLoadScript; $out = file_get_contents("{$IP}/resources/startup.js"); if ($context->getOnly() === 'scripts') { // Build load query for jquery and mediawiki modules $query = array('modules' => implode('|', array('jquery', 'mediawiki')), 'only' => 'scripts', 'lang' => $context->getLanguage(), 'skin' => $context->getSkin(), 'debug' => $context->getDebug() ? 'true' : 'false', 'version' => wfTimestamp(TS_ISO_8601_BASIC, round(max($context->getResourceLoader()->getModule('jquery')->getModifiedTime($context), $context->getResourceLoader()->getModule('mediawiki')->getModifiedTime($context)), -2))); // Ensure uniform query order ksort($query); // Startup function $configuration = $this->getConfig($context); $registrations = self::getModuleRegistrations($context); $out .= "var startUp = function() {\n" . "\t{$registrations}\n" . "\t" . Xml::encodeJsCall('mediaWiki.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; }
/** * Generate code for a response. * * @param $context ResourceLoaderContext Context in which to generate a response * @param array $modules List of module objects keyed by module name * @param array $missing List of requested module names that are unregistered (optional) * @return string Response data */ public function makeModuleResponse(ResourceLoaderContext $context, array $modules, array $missing = array()) { $out = ''; $exceptions = ''; $states = array(); if (!count($modules) && !count($missing)) { return "/* This file is the Web entry point for MediaWiki's ResourceLoader:\n <https://www.mediawiki.org/wiki/ResourceLoader>. In this request,\n no modules were requested. Max made me put this here. */"; } wfProfileIn(__METHOD__); // Pre-fetch blobs if ($context->shouldIncludeMessages()) { try { $blobs = MessageBlobStore::get($this, $modules, $context->getLanguage()); } catch (Exception $e) { MWExceptionHandler::logException($e); wfDebugLog('resourceloader', __METHOD__ . ": pre-fetching blobs from MessageBlobStore failed: {$e}"); $this->hasErrors = true; // Add exception to the output as a comment $exceptions .= self::formatException($e); } } else { $blobs = array(); } foreach ($missing as $name) { $states[$name] = 'missing'; } // Generate output $isRaw = false; foreach ($modules as $name => $module) { /** * @var $module ResourceLoaderModule */ wfProfileIn(__METHOD__ . '-' . $name); try { $scripts = ''; if ($context->shouldIncludeScripts()) { // If we are in debug mode, we'll want to return an array of URLs if possible // However, we can't do this if the module doesn't support it // We also can't do this if there is an only= parameter, because we have to give // the module a way to return a load.php URL without causing an infinite loop if ($context->getDebug() && !$context->getOnly() && $module->supportsURLLoading()) { $scripts = $module->getScriptURLsForDebug($context); } else { $scripts = $module->getScript($context); // rtrim() because there are usually a few line breaks after the last ';'. // A new line at EOF, a new line added by ResourceLoaderFileModule::readScriptFiles, etc. if (is_string($scripts) && strlen($scripts) && substr(rtrim($scripts), -1) !== ';') { // Append semicolon to prevent weird bugs caused by files not // terminating their statements right (bug 27054) $scripts .= ";\n"; } } } // Styles $styles = array(); if ($context->shouldIncludeStyles()) { // Don't create empty stylesheets like array( '' => '' ) for modules // that don't *have* any stylesheets (bug 38024). $stylePairs = $module->getStyles($context); if (count($stylePairs)) { // If we are in debug mode without &only= set, we'll want to return an array of URLs // See comment near shouldIncludeScripts() for more details if ($context->getDebug() && !$context->getOnly() && $module->supportsURLLoading()) { $styles = array('url' => $module->getStyleURLsForDebug($context)); } else { // Minify CSS before embedding in mw.loader.implement call // (unless in debug mode) if (!$context->getDebug()) { foreach ($stylePairs as $media => $style) { // Can be either a string or an array of strings. if (is_array($style)) { $stylePairs[$media] = array(); foreach ($style as $cssText) { if (is_string($cssText)) { $stylePairs[$media][] = $this->filter('minify-css', $cssText); } } } elseif (is_string($style)) { $stylePairs[$media] = $this->filter('minify-css', $style); } } } // Wrap styles into @media groups as needed and flatten into a numerical array $styles = array('css' => self::makeCombinedStyles($stylePairs)); } } } // Messages $messagesBlob = isset($blobs[$name]) ? $blobs[$name] : '{}'; // Append output switch ($context->getOnly()) { case 'scripts': if (is_string($scripts)) { // Load scripts raw... $out .= $scripts; } elseif (is_array($scripts)) { // ...except when $scripts is an array of URLs $out .= self::makeLoaderImplementScript($name, $scripts, array(), array()); } break; case 'styles': // We no longer seperate into media, they are all combined now with // custom media type groups into @media .. {} sections as part of the css string. // Module returns either an empty array or a numerical array with css strings. $out .= isset($styles['css']) ? implode('', $styles['css']) : ''; break; case 'messages': $out .= self::makeMessageSetScript(new XmlJsCode($messagesBlob)); break; default: $out .= self::makeLoaderImplementScript($name, $scripts, $styles, new XmlJsCode($messagesBlob)); break; } } catch (Exception $e) { MWExceptionHandler::logException($e); wfDebugLog('resourceloader', __METHOD__ . ": generating module package failed: {$e}"); $this->hasErrors = true; // Add exception to the output as a comment $exceptions .= self::formatException($e); // Respond to client with error-state instead of module implementation $states[$name] = 'error'; unset($modules[$name]); } $isRaw |= $module->isRaw(); wfProfileOut(__METHOD__ . '-' . $name); } // Update module states if ($context->shouldIncludeScripts() && !$context->getRaw() && !$isRaw) { if (count($modules) && $context->getOnly() === 'scripts') { // Set the state of modules loaded as only scripts to ready as // they don't have an mw.loader.implement wrapper that sets the state foreach ($modules as $name => $module) { $states[$name] = 'ready'; } } // Set the state of modules we didn't respond to with mw.loader.implement if (count($states)) { $out .= self::makeLoaderStateScript($states); } } if (!$context->getDebug()) { if ($context->getOnly() === 'styles') { $out = $this->filter('minify-css', $out); } else { $out = $this->filter('minify-js', $out); } } wfProfileOut(__METHOD__); return $exceptions . $out; }