Ejemplo n.º 1
0
 /**
  * @todo Document
  * @param array|string $modules One or more module names
  * @param string $only ResourceLoaderModule TYPE_ class constant
  * @param bool $useESI
  * @param array $extraQuery Array with extra query parameters to add to each
  *   request. array( param => value ).
  * @param bool $loadCall If true, output an (asynchronous) mw.loader.load()
  *   call rather than a "<script src='...'>" tag.
  * @return string The html "<script>", "<link>" and "<style>" tags
  */
 public function makeResourceLoaderLink($modules, $only, $useESI = false, array $extraQuery = array(), $loadCall = false)
 {
     $modules = (array) $modules;
     $links = array('html' => '', 'states' => array());
     if (!count($modules)) {
         return $links;
     }
     if (count($modules) > 1) {
         // Remove duplicate module requests
         $modules = array_unique($modules);
         // Sort module names so requests are more uniform
         sort($modules);
         if (ResourceLoader::inDebugMode()) {
             // Recursively call us for every item
             foreach ($modules as $name) {
                 $link = $this->makeResourceLoaderLink($name, $only, $useESI);
                 $links['html'] .= $link['html'];
                 $links['states'] += $link['states'];
             }
             return $links;
         }
     }
     if (!is_null($this->mTarget)) {
         $extraQuery['target'] = $this->mTarget;
     }
     // Create keyed-by-source and then keyed-by-group list of module objects from modules list
     $sortedModules = array();
     $resourceLoader = $this->getResourceLoader();
     $resourceLoaderUseESI = $this->getConfig()->get('ResourceLoaderUseESI');
     foreach ($modules as $name) {
         $module = $resourceLoader->getModule($name);
         # Check that we're allowed to include this module on this page
         if (!$module || $module->getOrigin() > $this->getAllowedModules(ResourceLoaderModule::TYPE_SCRIPTS) && $only == ResourceLoaderModule::TYPE_SCRIPTS || $module->getOrigin() > $this->getAllowedModules(ResourceLoaderModule::TYPE_STYLES) && $only == ResourceLoaderModule::TYPE_STYLES || $module->getOrigin() > $this->getAllowedModules(ResourceLoaderModule::TYPE_COMBINED) && $only == ResourceLoaderModule::TYPE_COMBINED || $this->mTarget && !in_array($this->mTarget, $module->getTargets())) {
             continue;
         }
         $sortedModules[$module->getSource()][$module->getGroup()][$name] = $module;
     }
     foreach ($sortedModules as $source => $groups) {
         foreach ($groups as $group => $grpModules) {
             // Special handling for user-specific groups
             $user = null;
             if (($group === 'user' || $group === 'private') && $this->getUser()->isLoggedIn()) {
                 $user = $this->getUser()->getName();
             }
             // Create a fake request based on the one we are about to make so modules return
             // correct timestamp and emptiness data
             $query = ResourceLoader::makeLoaderQuery(array(), $this->getLanguage()->getCode(), $this->getSkin()->getSkinName(), $user, null, ResourceLoader::inDebugMode(), $only === ResourceLoaderModule::TYPE_COMBINED ? null : $only, $this->isPrintable(), $this->getRequest()->getBool('handheld'), $extraQuery);
             $context = new ResourceLoaderContext($resourceLoader, new FauxRequest($query));
             // Extract modules that know they're empty and see if we have one or more
             // raw modules
             $isRaw = false;
             foreach ($grpModules as $key => $module) {
                 // Inline empty modules: since they're empty, just mark them as 'ready' (bug 46857)
                 // If we're only getting the styles, we don't need to do anything for empty modules.
                 if ($module->isKnownEmpty($context)) {
                     unset($grpModules[$key]);
                     if ($only !== ResourceLoaderModule::TYPE_STYLES) {
                         $links['states'][$key] = 'ready';
                     }
                 }
                 $isRaw |= $module->isRaw();
             }
             // If there are no non-empty modules, skip this group
             if (count($grpModules) === 0) {
                 continue;
             }
             // Inline private modules. These can't be loaded through load.php for security
             // reasons, see bug 34907. Note that these modules should be loaded from
             // getHeadScripts() before the first loader call. Otherwise other modules can't
             // properly use them as dependencies (bug 30914)
             if ($group === 'private') {
                 if ($only == ResourceLoaderModule::TYPE_STYLES) {
                     $links['html'] .= Html::inlineStyle($resourceLoader->makeModuleResponse($context, $grpModules));
                 } else {
                     $links['html'] .= ResourceLoader::makeInlineScript($resourceLoader->makeModuleResponse($context, $grpModules));
                 }
                 $links['html'] .= "\n";
                 continue;
             }
             // Special handling for the user group; because users might change their stuff
             // on-wiki like user pages, or user preferences; we need to find the highest
             // timestamp of these user-changeable modules so we can ensure cache misses on change
             // This should NOT be done for the site group (bug 27564) because anons get that too
             // and we shouldn't be putting timestamps in Squid-cached HTML
             $version = null;
             if ($group === 'user') {
                 $query['version'] = $resourceLoader->getCombinedVersion($context, array_keys($grpModules));
             }
             $query['modules'] = ResourceLoader::makePackedModulesString(array_keys($grpModules));
             $moduleContext = new ResourceLoaderContext($resourceLoader, new FauxRequest($query));
             $url = $resourceLoader->createLoaderURL($source, $moduleContext, $extraQuery);
             if ($useESI && $resourceLoaderUseESI) {
                 $esi = Xml::element('esi:include', array('src' => $url));
                 if ($only == ResourceLoaderModule::TYPE_STYLES) {
                     $link = Html::inlineStyle($esi);
                 } else {
                     $link = Html::inlineScript($esi);
                 }
             } else {
                 // Automatically select style/script elements
                 if ($only === ResourceLoaderModule::TYPE_STYLES) {
                     $link = Html::linkedStyle($url);
                 } elseif ($loadCall) {
                     $link = ResourceLoader::makeInlineScript(Xml::encodeJsCall('mw.loader.load', array($url, 'text/javascript', true)));
                 } else {
                     $link = Html::linkedScript($url);
                     if (!$context->getRaw() && !$isRaw) {
                         // Wrap only=script / only=combined requests in a conditional as
                         // browsers not supported by the startup module would unconditionally
                         // execute this module. Otherwise users will get "ReferenceError: mw is
                         // undefined" or "jQuery is undefined" from e.g. a "site" module.
                         $link = ResourceLoader::makeInlineScript(Xml::encodeJsCall('document.write', array($link)));
                     }
                     // For modules requested directly in the html via <link> or <script>,
                     // tell mw.loader they are being loading to prevent duplicate requests.
                     foreach ($grpModules as $key => $module) {
                         // Don't output state=loading for the startup module..
                         if ($key !== 'startup') {
                             $links['states'][$key] = 'loading';
                         }
                     }
                 }
             }
             if ($group == 'noscript') {
                 $links['html'] .= Html::rawElement('noscript', array(), $link) . "\n";
             } else {
                 $links['html'] .= $link . "\n";
             }
         }
     }
     return $links;
 }
    /**
     * @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;
    }
 /**
  * @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;
 }
Ejemplo n.º 4
0
 /**
  * @dataProvider providePackedModules
  */
 public function testMakePackedModulesString($desc, $modules, $packed)
 {
     $this->assertEquals($packed, ResourceLoader::makePackedModulesString($modules), $desc);
 }
 /**
  * Get the load URL of the startup modules.
  *
  * This is a helper for getScript(), but can also be called standalone, such
  * as when generating an AppCache manifest.
  *
  * @param ResourceLoaderContext $context
  * @return string
  */
 public static function getStartupModulesUrl(ResourceLoaderContext $context)
 {
     $rl = $context->getResourceLoader();
     $moduleNames = self::getStartupModules();
     $query = ['modules' => ResourceLoader::makePackedModulesString($moduleNames), 'only' => 'scripts', 'lang' => $context->getLanguage(), 'skin' => $context->getSkin(), 'debug' => $context->getDebug() ? 'true' : 'false', 'version' => $rl->getCombinedVersion($context, $moduleNames)];
     // Ensure uniform query order
     ksort($query);
     return wfAppendQuery(wfScript('load'), $query);
 }
Ejemplo n.º 6
0
 /**
  * TODO: Document
  * @param $skin Skin
  * @param $modules Array/string with the module name
  * @param $only String ResourceLoaderModule TYPE_ class constant
  * @param $useESI boolean
  * @return string html <script> and <style> tags
  */
 protected function makeResourceLoaderLink(Skin $skin, $modules, $only, $useESI = false)
 {
     global $wgLoadScript, $wgResourceLoaderUseESI;
     // Lazy-load ResourceLoader
     // TODO: Should this be a static function of ResourceLoader instead?
     $baseQuery = array('lang' => $this->getContext()->getLang()->getCode(), 'debug' => ResourceLoader::inDebugMode() ? 'true' : 'false', 'skin' => $skin->getSkinName(), 'only' => $only);
     // Propagate printable and handheld parameters if present
     if ($this->isPrintable()) {
         $baseQuery['printable'] = 1;
     }
     if ($this->getRequest()->getBool('handheld')) {
         $baseQuery['handheld'] = 1;
     }
     if (!count($modules)) {
         return '';
     }
     if (count($modules) > 1) {
         // Remove duplicate module requests
         $modules = array_unique((array) $modules);
         // Sort module names so requests are more uniform
         sort($modules);
         if (ResourceLoader::inDebugMode()) {
             // Recursively call us for every item
             $links = '';
             foreach ($modules as $name) {
                 $links .= $this->makeResourceLoaderLink($skin, $name, $only, $useESI);
             }
             return $links;
         }
     }
     // Create keyed-by-group list of module objects from modules list
     $groups = array();
     $resourceLoader = $this->getResourceLoader();
     foreach ((array) $modules as $name) {
         $module = $resourceLoader->getModule($name);
         # Check that we're allowed to include this module on this page
         if (!$module || $module->getOrigin() > $this->getAllowedModules(ResourceLoaderModule::TYPE_SCRIPTS) && $only == ResourceLoaderModule::TYPE_SCRIPTS || $module->getOrigin() > $this->getAllowedModules(ResourceLoaderModule::TYPE_STYLES) && $only == ResourceLoaderModule::TYPE_STYLES) {
             continue;
         }
         $group = $module->getGroup();
         if (!isset($groups[$group])) {
             $groups[$group] = array();
         }
         $groups[$group][$name] = $module;
     }
     $links = '';
     foreach ($groups as $group => $modules) {
         $query = $baseQuery;
         // Special handling for user-specific groups
         if (($group === 'user' || $group === 'private') && $this->getUser()->isLoggedIn()) {
             $query['user'] = $this->getUser()->getName();
         }
         // Create a fake request based on the one we are about to make so modules return
         // correct timestamp and emptiness data
         $context = new ResourceLoaderContext($resourceLoader, new FauxRequest($query));
         // Drop modules that know they're empty
         foreach ($modules as $key => $module) {
             if ($module->isKnownEmpty($context)) {
                 unset($modules[$key]);
             }
         }
         // If there are no modules left, skip this group
         if ($modules === array()) {
             continue;
         }
         $query['modules'] = ResourceLoader::makePackedModulesString(array_keys($modules));
         // Inline private modules. These can't be loaded through load.php for security
         // reasons, see bug 34907. Note that these modules should be loaded from
         // getHeadScripts() before the first loader call. Otherwise other modules can't
         // properly use them as dependencies (bug 30914)
         if ($group === 'private') {
             if ($only == ResourceLoaderModule::TYPE_STYLES) {
                 $links .= Html::inlineStyle($resourceLoader->makeModuleResponse($context, $modules));
             } else {
                 $links .= Html::inlineScript(ResourceLoader::makeLoaderConditionalScript($resourceLoader->makeModuleResponse($context, $modules)));
             }
             continue;
         }
         // Special handling for the user group; because users might change their stuff
         // on-wiki like user pages, or user preferences; we need to find the highest
         // timestamp of these user-changable modules so we can ensure cache misses on change
         // This should NOT be done for the site group (bug 27564) because anons get that too
         // and we shouldn't be putting timestamps in Squid-cached HTML
         if ($group === 'user') {
             // Get the maximum timestamp
             $timestamp = 1;
             foreach ($modules as $module) {
                 $timestamp = max($timestamp, $module->getModifiedTime($context));
             }
             // Add a version parameter so cache will break when things change
             $query['version'] = wfTimestamp(TS_ISO_8601_BASIC, $timestamp);
         }
         // Make queries uniform in order
         ksort($query);
         $url = wfAppendQuery($wgLoadScript, $query);
         // Prevent the IE6 extension check from being triggered (bug 28840)
         // by appending a character that's invalid in Windows extensions ('*')
         $url .= '&*';
         if ($useESI && $wgResourceLoaderUseESI) {
             $esi = Xml::element('esi:include', array('src' => $url));
             if ($only == ResourceLoaderModule::TYPE_STYLES) {
                 $link = Html::inlineStyle($esi);
             } else {
                 $link = Html::inlineScript($esi);
             }
         } else {
             // Automatically select style/script elements
             if ($only === ResourceLoaderModule::TYPE_STYLES) {
                 $link = Html::linkedStyle($url);
             } else {
                 $link = Html::linkedScript($url);
             }
         }
         if ($group == 'noscript') {
             $links .= Html::rawElement('noscript', array(), $link) . "\n";
         } else {
             $links .= $link . "\n";
         }
     }
     return $links;
 }
Ejemplo n.º 7
0
 function outputInlineScript($moduleList)
 {
     $o = "";
     $modules = array();
     $resolvedModuleDependencyList = $this->getModuleDependencyList($moduleList);
     // "Fake" the request headers as ResourceLoaderContext derives it's data for module resolving from them
     $_GET['only'] = NULL;
     $_GET['modules'] = ResourceLoader::makePackedModulesString($resolvedModuleDependencyList);
     $fauxRequest = new WebRequest();
     $resourceLoader = new MwEmbedResourceLoader();
     foreach ($resolvedModuleDependencyList as $moduleName) {
         $modules[$moduleName] = $resourceLoader->getModule($moduleName);
     }
     $s = $resourceLoader->makeModuleResponse(new MwEmbedResourceLoaderContext($resourceLoader, $fauxRequest), $modules, array());
     $o .= 'window.inlineScript = true;';
     $o .= $s;
     $o .= ResourceLoader::makeLoaderStateScript(array_fill_keys($resolvedModuleDependencyList, 'ready'));
     return $o;
 }
 /**
  * Get the load URL of the startup modules.
  *
  * This is a helper for getScript(), but can also be called standalone, such
  * as when generating an AppCache manifest.
  *
  * @param ResourceLoaderContext $context
  * @return string
  */
 public static function getStartupModulesUrl(ResourceLoaderContext $context)
 {
     // The core modules:
     $moduleNames = array('jquery', 'mediawiki');
     wfRunHooks('ResourceLoaderGetStartupModules', array(&$moduleNames), '1.23');
     // Get the latest version
     $loader = $context->getResourceLoader();
     $version = 0;
     foreach ($moduleNames as $moduleName) {
         $version = max($version, $loader->getModule($moduleName)->getModifiedTime($context));
     }
     $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);
     return wfAppendQuery(wfScript('load'), $query);
 }
 /**
  * @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;
 }