[BUGFIX] Fix several typos in php comments
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Page / PageRenderer.php
index 8661bf6..249344c 100644 (file)
@@ -22,10 +22,10 @@ use TYPO3\CMS\Core\Core\Environment;
 use TYPO3\CMS\Core\Localization\Locales;
 use TYPO3\CMS\Core\Localization\LocalizationFactory;
 use TYPO3\CMS\Core\MetaTag\MetaTagManagerRegistry;
+use TYPO3\CMS\Core\Package\PackageManager;
 use TYPO3\CMS\Core\Resource\ResourceCompressor;
 use TYPO3\CMS\Core\Service\MarkerBasedTemplateService;
 use TYPO3\CMS\Core\SingletonInterface;
-use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\PathUtility;
 
@@ -1019,11 +1019,8 @@ class PageRenderer implements SingletonInterface
      * @param bool $defer Flag if property 'defer="defer"' should be added to JavaScript tags
      * @param string $crossorigin CORS settings attribute
      */
-    public function addJsLibrary($name, $file, $type = 'text/javascript', $compress = false, $forceOnTop = false, $allWrap = '', $excludeFromConcatenation = false, $splitChar = '|', $async = false, $integrity = '', $defer = false, $crossorigin = '')
+    public function addJsLibrary($name, $file, $type = '', $compress = false, $forceOnTop = false, $allWrap = '', $excludeFromConcatenation = false, $splitChar = '|', $async = false, $integrity = '', $defer = false, $crossorigin = '')
     {
-        if (!$type) {
-            $type = 'text/javascript';
-        }
         if (!in_array(strtolower($name), $this->jsLibs)) {
             $this->jsLibs[strtolower($name)] = [
                 'file' => $file,
@@ -1058,11 +1055,8 @@ class PageRenderer implements SingletonInterface
      * @param bool $defer Flag if property 'defer="defer"' should be added to JavaScript tags
      * @param string $crossorigin CORS settings attribute
      */
-    public function addJsFooterLibrary($name, $file, $type = 'text/javascript', $compress = false, $forceOnTop = false, $allWrap = '', $excludeFromConcatenation = false, $splitChar = '|', $async = false, $integrity = '', $defer = false, $crossorigin = '')
+    public function addJsFooterLibrary($name, $file, $type = '', $compress = false, $forceOnTop = false, $allWrap = '', $excludeFromConcatenation = false, $splitChar = '|', $async = false, $integrity = '', $defer = false, $crossorigin = '')
     {
-        if (!$type) {
-            $type = 'text/javascript';
-        }
         $name .= '_jsFooterLibrary';
         if (!in_array(strtolower($name), $this->jsLibs)) {
             $this->jsLibs[strtolower($name)] = [
@@ -1097,11 +1091,8 @@ class PageRenderer implements SingletonInterface
      * @param bool $defer Flag if property 'defer="defer"' should be added to JavaScript tags
      * @param string $crossorigin CORS settings attribute
      */
-    public function addJsFile($file, $type = 'text/javascript', $compress = true, $forceOnTop = false, $allWrap = '', $excludeFromConcatenation = false, $splitChar = '|', $async = false, $integrity = '', $defer = false, $crossorigin = '')
+    public function addJsFile($file, $type = '', $compress = true, $forceOnTop = false, $allWrap = '', $excludeFromConcatenation = false, $splitChar = '|', $async = false, $integrity = '', $defer = false, $crossorigin = '')
     {
-        if (!$type) {
-            $type = 'text/javascript';
-        }
         if (!isset($this->jsFiles[$file])) {
             $this->jsFiles[$file] = [
                 'file' => $file,
@@ -1135,11 +1126,8 @@ class PageRenderer implements SingletonInterface
      * @param bool $defer Flag if property 'defer="defer"' should be added to JavaScript tags
      * @param string $crossorigin CORS settings attribute
      */
-    public function addJsFooterFile($file, $type = 'text/javascript', $compress = true, $forceOnTop = false, $allWrap = '', $excludeFromConcatenation = false, $splitChar = '|', $async = false, $integrity = '', $defer = false, $crossorigin = '')
+    public function addJsFooterFile($file, $type = '', $compress = true, $forceOnTop = false, $allWrap = '', $excludeFromConcatenation = false, $splitChar = '|', $async = false, $integrity = '', $defer = false, $crossorigin = '')
     {
-        if (!$type) {
-            $type = 'text/javascript';
-        }
         if (!isset($this->jsFiles[$file])) {
             $this->jsFiles[$file] = [
                 'file' => $file,
@@ -1294,16 +1282,16 @@ class PageRenderer implements SingletonInterface
             return;
         }
 
-        $loadedExtensions = ExtensionManagementUtility::getLoadedExtensionListArray();
+        $packages = GeneralUtility::makeInstance(PackageManager::class)->getActivePackages();
         $isDevelopment = GeneralUtility::getApplicationContext()->isDevelopment();
-        $cacheIdentifier = 'requireJS_' . md5(implode(',', $loadedExtensions) . ($isDevelopment ? ':dev' : '') . GeneralUtility::getIndpEnv('TYPO3_REQUEST_SCRIPT'));
+        $cacheIdentifier = 'requireJS_' . md5(implode(',', array_keys($packages)) . ($isDevelopment ? ':dev' : '') . GeneralUtility::getIndpEnv('TYPO3_REQUEST_SCRIPT'));
         /** @var FrontendInterface $cache */
         $cache = static::$cache ?? GeneralUtility::makeInstance(CacheManager::class)->getCache('assets');
         $requireJsConfig = $cache->get($cacheIdentifier);
 
         // if we did not get a configuration from the cache, compute and store it in the cache
         if (!isset($requireJsConfig['internal']) || !isset($requireJsConfig['public'])) {
-            $requireJsConfig = $this->computeRequireJsConfig($isDevelopment, $loadedExtensions);
+            $requireJsConfig = $this->computeRequireJsConfig($isDevelopment, $packages);
             $cache->set($cacheIdentifier, $requireJsConfig);
         }
 
@@ -1317,10 +1305,10 @@ class PageRenderer implements SingletonInterface
      * resource folders plus some additional generic configuration.
      *
      * @param bool $isDevelopment
-     * @param array $loadedExtensions
+     * @param array $packages
      * @return array The RequireJS configuration
      */
-    protected function computeRequireJsConfig($isDevelopment, array $loadedExtensions)
+    protected function computeRequireJsConfig($isDevelopment, array $packages)
     {
         // load all paths to map to package names / namespaces
         $requireJsConfig = [
@@ -1329,13 +1317,7 @@ class PageRenderer implements SingletonInterface
             'internalNames' => [],
         ];
 
-        // In order to avoid browser caching of JS files, adding a GET parameter to the files loaded via requireJS
-        if ($isDevelopment) {
-            $requireJsConfig['public']['urlArgs'] = 'bust=' . $GLOBALS['EXEC_TIME'];
-        } else {
-            $requireJsConfig['public']['urlArgs'] = 'bust=' . GeneralUtility::hmac(TYPO3_version . Environment::getProjectPath());
-        }
-        $corePath = ExtensionManagementUtility::extPath('core', 'Resources/Public/JavaScript/Contrib/');
+        $corePath = $packages['core']->getPackagePath() . 'Resources/Public/JavaScript/Contrib/';
         $corePath = PathUtility::getAbsoluteWebPath($corePath);
         // first, load all paths for the namespaces, and configure contrib libs.
         $requireJsConfig['public']['paths'] = [
@@ -1354,18 +1336,20 @@ class PageRenderer implements SingletonInterface
             'jquery/autocomplete' => $corePath . 'jquery.autocomplete',
             'd3' => $corePath . 'd3/d3',
             'Sortable' => $corePath . 'Sortable.min',
+            'broadcastchannel' => $corePath . '/broadcastchannel-polyfill',
         ];
         $requireJsConfig['public']['waitSeconds'] = 30;
         $requireJsConfig['public']['typo3BaseUrl'] = false;
         $publicPackageNames = ['core', 'frontend', 'backend'];
-        foreach ($loadedExtensions as $packageName) {
-            $jsPath = 'EXT:' . $packageName . '/Resources/Public/JavaScript/';
-            $absoluteJsPath = GeneralUtility::getFileAbsFileName($jsPath);
+        $requireJsExtensionVersions = [];
+        foreach ($packages as $packageName => $package) {
+            $absoluteJsPath = $package->getPackagePath() . 'Resources/Public/JavaScript/';
             $fullJsPath = PathUtility::getAbsoluteWebPath($absoluteJsPath);
             $fullJsPath = rtrim($fullJsPath, '/');
             if (!empty($fullJsPath) && file_exists($absoluteJsPath)) {
                 $type = in_array($packageName, $publicPackageNames, true) ? 'public' : 'internal';
                 $requireJsConfig[$type]['paths']['TYPO3/CMS/' . GeneralUtility::underscoredToUpperCamelCase($packageName)] = $fullJsPath;
+                $requireJsExtensionVersions[] = $package->getPackageKey() . ':' . $package->getPackageMetadata()->getVersion();
             }
         }
         // sanitize module names in internal 'paths'
@@ -1382,6 +1366,15 @@ class PageRenderer implements SingletonInterface
             $internalPathModuleNames
         );
 
+        // Add a GET parameter to the files loaded via requireJS in order to avoid browser caching of JS files
+        if ($isDevelopment) {
+            $requireJsConfig['public']['urlArgs'] = 'bust=' . $GLOBALS['EXEC_TIME'];
+        } else {
+            $requireJsConfig['public']['urlArgs'] = 'bust=' . GeneralUtility::hmac(
+                Environment::getProjectPath() . implode('|', $requireJsExtensionVersions)
+            );
+        }
+
         // check if additional AMD modules need to be loaded if a single AMD module is initialized
         if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['RequireJS']['postInitializationModules'] ?? false)) {
             $this->addInlineSettingArray(
@@ -1448,14 +1441,14 @@ class PageRenderer implements SingletonInterface
         // directly after that, include the require.js file
         $html .= '<script src="'
             . $this->processJsFile($this->requireJsPath . 'require.js')
-            . '" type="text/javascript"></script>' . LF;
+            . '"></script>' . LF;
 
         if (!empty($requireJsConfig['typo3BaseUrl'])) {
             $html .= '<script src="'
                 . $this->processJsFile(
                     'EXT:core/Resources/Public/JavaScript/requirejs-loader.js'
                 )
-                . '" type="text/javascript"></script>' . LF;
+                . '"></script>' . LF;
         }
 
         return $html;
@@ -1688,7 +1681,7 @@ class PageRenderer implements SingletonInterface
     /**
      * Render the page but not the JavaScript and CSS Files
      *
-     * @param string $substituteHash The hash that is used for the placehoder markers
+     * @param string $substituteHash The hash that is used for the placeholder markers
      * @internal
      * @return string Content of rendered section
      */
@@ -1757,7 +1750,7 @@ class PageRenderer implements SingletonInterface
     /**
      * Renders all JavaScript and CSS
      *
-     * @return array<string>
+     * @return array|string[]
      */
     protected function renderJavaScriptAndCss()
     {
@@ -1838,7 +1831,7 @@ class PageRenderer implements SingletonInterface
     /**
      * Fills the marker array with the given strings and trims each value
      *
-     * @param string $substituteHash The hash that is used for the placehoder markers
+     * @param string $substituteHash The hash that is used for the placeholder markers
      * @return array Marker array
      */
     protected function getPreparedMarkerArrayForPageWithUncachedObjects($substituteHash)
@@ -2110,9 +2103,9 @@ class PageRenderer implements SingletonInterface
     }
 
     /**
-     * Render JavaScipt libraries
+     * Render JavaScript libraries
      *
-     * @return array<string> jsLibs and jsFooterLibs strings
+     * @return array|string[] jsLibs and jsFooterLibs strings
      */
     protected function renderAdditionalJavaScriptLibraries()
     {
@@ -2156,7 +2149,7 @@ class PageRenderer implements SingletonInterface
     /**
      * Render JavaScript files
      *
-     * @return array<string> jsFiles and jsFooterFiles strings
+     * @return array|string[] jsFiles and jsFooterFiles strings
      */
     protected function renderJavaScriptFiles()
     {
@@ -2165,11 +2158,12 @@ class PageRenderer implements SingletonInterface
         if (!empty($this->jsFiles)) {
             foreach ($this->jsFiles as $file => $properties) {
                 $file = $this->getStreamlinedFileName($file);
+                $type = $properties['type'] ? ' type="' . htmlspecialchars($properties['type']) . '"' : '';
                 $async = $properties['async'] ? ' async="async"' : '';
                 $defer = $properties['defer'] ? ' defer="defer"' : '';
                 $integrity = $properties['integrity'] ? ' integrity="' . htmlspecialchars($properties['integrity']) . '"' : '';
                 $crossorigin = $properties['crossorigin'] ? ' crossorigin="' . htmlspecialchars($properties['crossorigin']) . '"' : '';
-                $tag = '<script src="' . htmlspecialchars($file) . '" type="' . htmlspecialchars($properties['type']) . '"' . $async . $defer . $integrity . $crossorigin . '></script>';
+                $tag = '<script src="' . htmlspecialchars($file) . '"' . $type . $async . $defer . $integrity . $crossorigin . '></script>';
                 if ($properties['allWrap']) {
                     $wrapArr = explode($properties['splitChar'] ?: '|', $properties['allWrap'], 2);
                     $tag = $wrapArr[0] . $tag . $wrapArr[1];
@@ -2200,7 +2194,7 @@ class PageRenderer implements SingletonInterface
     /**
      * Render inline JavaScript
      *
-     * @return array<string> jsInline and jsFooterInline string
+     * @return array|string[] jsInline and jsFooterInline string
      */
     protected function renderInlineJavaScript()
     {
@@ -2632,7 +2626,7 @@ class PageRenderer implements SingletonInterface
     }
 
     /**
-     * Creates an CSS inline tag
+     * Creates a CSS inline tag
      *
      * @param string $file the filename to process
      * @param array $properties