diff --git a/administrator/templates/atum/component.php b/administrator/templates/atum/component.php index a4dcfc1af0db2..962ea7c99027a 100644 --- a/administrator/templates/atum/component.php +++ b/administrator/templates/atum/component.php @@ -33,7 +33,9 @@ - + + + diff --git a/administrator/templates/atum/error_full.php b/administrator/templates/atum/error_full.php index 5c9b78579c389..342f9e903e57b 100644 --- a/administrator/templates/atum/error_full.php +++ b/administrator/templates/atum/error_full.php @@ -82,6 +82,7 @@ + @@ -196,6 +197,5 @@ - diff --git a/administrator/templates/atum/error_login.php b/administrator/templates/atum/error_login.php index 62a7b2bf0e4fe..331d5b96c4c96 100644 --- a/administrator/templates/atum/error_login.php +++ b/administrator/templates/atum/error_login.php @@ -85,6 +85,7 @@ + @@ -168,6 +169,5 @@ - diff --git a/administrator/templates/atum/index.php b/administrator/templates/atum/index.php index 4587ef5a59dfa..fb16d5efce00e 100644 --- a/administrator/templates/atum/index.php +++ b/administrator/templates/atum/index.php @@ -84,6 +84,7 @@ + @@ -178,6 +179,5 @@ - diff --git a/administrator/templates/atum/login.php b/administrator/templates/atum/login.php index ce73881ffff8b..8f5deeaa56235 100644 --- a/administrator/templates/atum/login.php +++ b/administrator/templates/atum/login.php @@ -80,6 +80,7 @@ + @@ -140,6 +141,5 @@ - diff --git a/build/build-modules-js/settings.json b/build/build-modules-js/settings.json index 276c31954dd8f..0c90b92ac5b3d 100644 --- a/build/build-modules-js/settings.json +++ b/build/build-modules-js/settings.json @@ -82,7 +82,8 @@ "type": "script", "uri": "bootstrap.min.js", "dependencies": [ - "jquery" + "jquery", + "jquery-noconflict" ] }, { @@ -90,7 +91,8 @@ "type": "script", "uri": "bootstrap.bundle.min.js", "dependencies": [ - "jquery" + "jquery", + "jquery-noconflict" ] } ], @@ -418,7 +420,8 @@ "type": "script", "uri": "jquery.minicolors.min.js", "dependencies": [ - "jquery" + "jquery", + "jquery-noconflict" ], "attributes": { "defer": true @@ -434,7 +437,8 @@ } ], "dependencies": [ - "jquery" + "jquery", + "jquery-noconflict" ], "licenseFilename": "LICENSE.md" }, @@ -478,7 +482,8 @@ "type": "script", "uri": "chosen.jquery.js", "dependencies": [ - "jquery" + "jquery", + "jquery-noconflict" ] }, { diff --git a/build/media_source/com_associations/joomla.asset.json b/build/media_source/com_associations/joomla.asset.json index f28882529f2c9..893a01de118f9 100644 --- a/build/media_source/com_associations/joomla.asset.json +++ b/build/media_source/com_associations/joomla.asset.json @@ -49,7 +49,8 @@ "uri": "com_associations/sidebyside.min.js", "dependencies": [ "core", - "jquery" + "jquery", + "jquery-noconflict" ], "attributes": { "defer": true diff --git a/build/media_source/com_finder/joomla.asset.json b/build/media_source/com_finder/joomla.asset.json index 0e7fa78a3c3f0..eee251775b542 100644 --- a/build/media_source/com_finder/joomla.asset.json +++ b/build/media_source/com_finder/joomla.asset.json @@ -43,7 +43,8 @@ "uri": "com_finder/finder-edit.min.js", "dependencies": [ "core", - "jquery" + "jquery", + "jquery-noconflict" ], "attributes": { "defer": true @@ -55,7 +56,8 @@ "uri": "com_finder/index.min.js", "dependencies": [ "core", - "jquery" + "jquery", + "jquery-noconflict" ], "attributes": { "defer": true diff --git a/build/media_source/com_joomlaupdate/joomla.asset.json b/build/media_source/com_joomlaupdate/joomla.asset.json index 0f3f6d679889a..cc547c7e385a4 100644 --- a/build/media_source/com_joomlaupdate/joomla.asset.json +++ b/build/media_source/com_joomlaupdate/joomla.asset.json @@ -45,6 +45,7 @@ "dependencies": [ "core", "jquery", + "jquery-noconflict", "com_joomlaupdate.encryption" ], "attributes": { diff --git a/build/media_source/com_menus/joomla.asset.json b/build/media_source/com_menus/joomla.asset.json index 976cdc65ee386..1ffff76edbc00 100644 --- a/build/media_source/com_menus/joomla.asset.json +++ b/build/media_source/com_menus/joomla.asset.json @@ -76,7 +76,8 @@ "uri": "com_menus/admin-menus-default.min.js", "dependencies": [ "core", - "jquery" + "jquery", + "jquery-noconflict" ], "attributes": { "defer": true diff --git a/build/media_source/legacy/joomla.asset.json b/build/media_source/legacy/joomla.asset.json index 4f9773ecaad90..255a587896924 100644 --- a/build/media_source/legacy/joomla.asset.json +++ b/build/media_source/legacy/joomla.asset.json @@ -22,7 +22,8 @@ "name": "joomla.frontediting", "type": "script", "dependencies": [ - "jquery" + "jquery", + "jquery-noconflict" ], "uri": "legacy/frontediting.min.js", "attributes": { @@ -41,7 +42,8 @@ "name": "joomla.treeselectmenu", "type": "script", "dependencies": [ - "jquery" + "jquery", + "jquery-noconflict" ], "uri": "legacy/treeselectmenu.min.js", "attributes": { diff --git a/libraries/src/Document/Document.php b/libraries/src/Document/Document.php index 336edd6595b5f..4d1ae63befd8d 100644 --- a/libraries/src/Document/Document.php +++ b/libraries/src/Document/Document.php @@ -534,6 +534,14 @@ public function addScript($url, $options = array(), $attribs = array()) $attribs['type'] = 'text/javascript'; } + // Default to defer. + if ((!isset($attribs['type']) || $attribs['type'] !== 'module') + && (!isset($attribs['defer']) || $attribs['defer'] !== false) + && !isset($attribs['async'])) + { + $attribs['defer'] = ''; + } + $this->_scripts[$url] = isset($this->_scripts[$url]) ? array_replace($this->_scripts[$url], $attribs) : $attribs; $this->_scripts[$url]['options'] = isset($this->_scripts[$url]['options']) ? array_replace($this->_scripts[$url]['options'], $options) : $options; diff --git a/libraries/src/Document/HtmlDocument.php b/libraries/src/Document/HtmlDocument.php index 8e4d9e23ed75c..92a7cb71eb626 100644 --- a/libraries/src/Document/HtmlDocument.php +++ b/libraries/src/Document/HtmlDocument.php @@ -34,7 +34,7 @@ class HtmlDocument extends Document * @var array * @since 1.7.0 */ - public $_links = array(); + public $_links = []; /** * Array of custom tags @@ -42,7 +42,7 @@ class HtmlDocument extends Document * @var array * @since 1.7.0 */ - public $_custom = array(); + public $_custom = []; /** * Name of the template @@ -98,7 +98,7 @@ class HtmlDocument extends Document * @var array * @since 1.7.0 */ - protected $_template_tags = array(); + protected $_template_tags = []; /** * Integer with caching setting @@ -123,7 +123,7 @@ class HtmlDocument extends Document * * @since 1.7.0 */ - public function __construct($options = array()) + public function __construct($options = []) { parent::__construct($options); @@ -143,7 +143,7 @@ public function __construct($options = array()) */ public function getHeadData() { - $data = array(); + $data = []; $data['title'] = $this->title; $data['description'] = $this->description; $data['link'] = $this->link; @@ -203,14 +203,14 @@ public function resetHeadData($types = null) $this->title = ''; $this->description = ''; $this->link = ''; - $this->_metaTags = array(); - $this->_links = array(); - $this->_styleSheets = array(); - $this->_style = array(); - $this->_scripts = array(); - $this->_script = array(); - $this->_custom = array(); - $this->scriptOptions = array(); + $this->_metaTags = []; + $this->_links = []; + $this->_styleSheets = []; + $this->_style = []; + $this->_scripts = []; + $this->_script = []; + $this->_custom = []; + $this->scriptOptions = []; } if (\is_array($types)) @@ -256,11 +256,11 @@ private function resetHeadDatum($type) case 'script': case 'custom': $realType = '_' . $type; - $this->{$realType} = array(); + $this->{$realType} = []; break; case 'scriptOptions': - $this->{$type} = array(); + $this->{$type} = []; break; } } @@ -325,7 +325,7 @@ public function setHeadData($data) * * @param array $data The document head data in array form * - * @return HtmlDocument|null instance of $this to allow chaining or null for empty input data + * @return HtmlDocument|void instance of $this to allow chaining or null for empty input data * * @since 1.7.0 */ @@ -451,7 +451,7 @@ public function mergeHeadData($data) * * @since 1.7.0 */ - public function addHeadLink($href, $relation, $relType = 'rel', $attribs = array()) + public function addHeadLink($href, $relation, $relType = 'rel', $attribs = []) { $this->_links[$href]['relation'] = $relation; $this->_links[$href]['relType'] = $relType; @@ -539,7 +539,7 @@ public function setHtml5($state) * * @since 1.7.0 */ - public function getBuffer($type = null, $name = null, $attribs = array()) + public function getBuffer($type = null, $name = null, $attribs = []) { // If no type is specified, return the whole buffer if ($type === null) @@ -569,7 +569,7 @@ public function getBuffer($type = null, $name = null, $attribs = array()) } else { - $options = array(); + $options = []; $options['nopathway'] = 1; $options['nomodules'] = 1; $options['modulemode'] = 1; @@ -602,13 +602,13 @@ public function getBuffer($type = null, $name = null, $attribs = array()) * * @since 1.7.0 */ - public function setBuffer($content, $options = array()) + public function setBuffer($content, $options = []) { // The following code is just for backward compatibility. if (\func_num_args() > 1 && !\is_array($options)) { $args = \func_get_args(); - $options = array(); + $options = []; $options['type'] = $args[1]; $options['name'] = $args[2] ?? null; $options['title'] = $args[3] ?? null; @@ -628,7 +628,7 @@ public function setBuffer($content, $options = array()) * * @since 1.7.0 */ - public function parse($params = array()) + public function parse($params = []) { return $this->_fetchTemplate($params)->_parseTemplate(); } @@ -643,7 +643,7 @@ public function parse($params = array()) * * @since 1.7.0 */ - public function render($caching = false, $params = array()) + public function render($caching = false, $params = []) { $this->_caching = $caching; @@ -785,7 +785,7 @@ protected function _loadTemplate($directory, $filename) * * @since 1.7.0 */ - protected function _fetchTemplate($params = array()) + protected function _fetchTemplate($params = []) { // Check $directory = $params['directory'] ?? 'templates'; @@ -841,7 +841,7 @@ protected function _fetchTemplate($params = array()) */ protected function _parseTemplate() { - $matches = array(); + $matches = []; if (preg_match_all('##iU', $this->_template, $matches)) { @@ -853,7 +853,7 @@ protected function _parseTemplate() for ($i = \count($matches[0]) - 1; $i >= 0; $i--) { $type = $matches[1][$i]; - $attribs = empty($matches[2][$i]) ? array() : Utility::parseAttributes($matches[2][$i]); + $attribs = empty($matches[2][$i]) ? [] : Utility::parseAttributes($matches[2][$i]); $name = $attribs['name'] ?? null; // Separate buffers to be executed first and last diff --git a/libraries/src/Document/Renderer/Html/ComponentRenderer.php b/libraries/src/Document/Renderer/Html/ComponentRenderer.php index 5d13b2e03e19e..e707b9a96748c 100644 --- a/libraries/src/Document/Renderer/Html/ComponentRenderer.php +++ b/libraries/src/Document/Renderer/Html/ComponentRenderer.php @@ -11,6 +11,7 @@ \defined('JPATH_PLATFORM') or die; use Joomla\CMS\Document\DocumentRenderer; +use Joomla\CMS\Factory; /** * HTML document renderer for the component output @@ -19,6 +20,8 @@ */ class ComponentRenderer extends DocumentRenderer { + use FixAssets; + /** * Renders a component script and returns the results as a string * @@ -30,8 +33,16 @@ class ComponentRenderer extends DocumentRenderer * * @since 3.5 */ - public function render($component = null, $params = array(), $content = null) + public function render($component = '', $params = array(), $content = '') { + $app = Factory::getApplication(); + $template = $app->getTemplate(true); + + if ($template->params->getBool('joomla_skip_assets_processing_components', true)) + { + return $this->fixAssets($content); + } + return $content; } } diff --git a/libraries/src/Document/Renderer/Html/FixAssets.php b/libraries/src/Document/Renderer/Html/FixAssets.php new file mode 100644 index 0000000000000..f9ea8c5311123 --- /dev/null +++ b/libraries/src/Document/Renderer/Html/FixAssets.php @@ -0,0 +1,227 @@ +getWebAssetManager(); + + \libxml_use_internal_errors(true); + $dom->loadHtml($asset); + \libxml_clear_errors(); + + $script = $dom->getElementsByTagName('script')->item(0); + $style = $dom->getElementsByTagName('style')->item(0); + + // Case script + if ($script) + { + $src = $script->getAttribute('src'); + + if ($src) + { + $attrs = []; + + for ($i = 0; $i < $script->attributes->length; ++$i) + { + $node = $script->attributes->item($i); + + if ($node->nodeName !== 'src') + { + $attrs[$node->nodeName] = $node->nodeValue; + } + } + + // Defer by default + if (!isset($attrs['defer']) && (!isset($attrs['type']) || $attrs['type'] !== 'module') && !isset($attrs['data-joomla-no-defer'])) + { + $attrs['defer'] = ''; + } + + // Add missing nonce + if (!isset($attrs['nonce'])) + { + $attrs['nonce'] = $this->_doc->nonce; + } + + if (!$inPlace) + { + $wa->registerAndUseScript( + md5($src), + $src, + [], + $attrs + ); + + return ''; + } + + return $dom->saveXML(); + } + else + { + $type = $script->getAttribute('type'); + $noDefer = $script->hasAttribute('data-joomla-no-defer'); + + if ($noDefer || $type === 'module') + { + // Add missing nonce + if (!isset($attrs['nonce'])) + { + $attrs['nonce'] = $this->_doc->nonce; + } + + return $dom->saveXML(); + } + + // Add missing nonce + if (!isset($attrs['nonce'])) + { + $attrs['nonce'] = $this->_doc->cspNonce; + } + + if (in_array($type, ["application/javascript", "text/javascript", ''])) + { + if (!$inPlace) + { + $wa->addInlineScript( + $script->nodeValue, + ['name' => md5($script->nodeValue)], + [], + [] + ); + + return ''; + } + + return $dom->saveXML(); + } + } + + return ''; + } + + // Case inline style + if ($style) + { + // Add missing nonce + if (!isset($attrs['nonce'])) + { + $attrs['nonce'] = $this->_doc->nonce; + } + + if ($style->hasAttribute('data-joomla-no-defer')) + { + return $dom->saveXML(); + } + + if (!$inPlace) + { + $wa->addInlineStyle( + $style->nodeValue, + ['name' => md5($style->nodeValue)], + [], + [] + ); + + return ''; + } + + return $dom->saveXML(); + } + } + + /** + * Method that fixes the head assets inserted with addCustomTag + * + * @return void + */ + public function fixCustom() + { + foreach ($this->_doc->_custom as $id => $custom) + { + $result = $this->fixAsset($custom, false); + + if (!$result) + { + // Remove from the array + unset($this->_doc->_custom[$id]); + } + } + } + + /** + * Method that fixes the static assets in an html fragment + * + * @param string $content The html fragment + * + * @return string + */ + public function fixAssets($content) + { + preg_match_all('//i', $content, $scripts); + preg_match_all('//i', $content, $styles); + + // Bail quickly + if (count($scripts[0]) === 0 && count($styles[0]) === 0) + { + return $content; + } + + if (count($scripts[0])) + { + foreach ($scripts[0] as $script) + { + $newSrcipt = $this->fixAsset($script, true); + + if ($newSrcipt !== '') + { + preg_replace($script, $newSrcipt, $content); + } + } + } + + if (count($styles[0])) + { + foreach ($styles[0] as $style) + { + $newStyle = $this->fixAsset($style, true); + + if ($newStyle !== '') + { + preg_replace($style, $newStyle, $content); + } + } + } + + return $content; + } +} diff --git a/libraries/src/Document/Renderer/Html/HeadRenderer.php b/libraries/src/Document/Renderer/Html/HeadRenderer.php index 483a0440709d6..53f5e0dbfb12a 100644 --- a/libraries/src/Document/Renderer/Html/HeadRenderer.php +++ b/libraries/src/Document/Renderer/Html/HeadRenderer.php @@ -30,13 +30,10 @@ class HeadRenderer extends DocumentRenderer * * @since 3.5 */ - public function render($head, $params = array(), $content = null) + public function render($head, $params = array(), $content = '') { - $buffer = ''; - $buffer .= $this->_doc->loadRenderer('metas')->render($head, $params, $content); - $buffer .= $this->_doc->loadRenderer('styles')->render($head, $params, $content); - $buffer .= $this->_doc->loadRenderer('scripts')->render($head, $params, $content); - - return $buffer; + return $this->_doc->loadRenderer('metas')->render($head, $params, $content) . + $this->_doc->loadRenderer('styles')->render($head, $params, $content) . + $this->_doc->loadRenderer('scripts')->render($head, $params, $content); } } diff --git a/libraries/src/Document/Renderer/Html/MessageRenderer.php b/libraries/src/Document/Renderer/Html/MessageRenderer.php index 247a72d03313e..f74c12831c3e4 100644 --- a/libraries/src/Document/Renderer/Html/MessageRenderer.php +++ b/libraries/src/Document/Renderer/Html/MessageRenderer.php @@ -33,7 +33,7 @@ class MessageRenderer extends DocumentRenderer * * @since 3.5 */ - public function render($name, $params = array(), $content = null) + public function render($name, $params = [], $content = '') { $msgList = $this->getData(); $displayData = array( @@ -71,7 +71,7 @@ public function render($name, $params = array(), $content = null) private function getData() { // Initialise variables. - $lists = array(); + $lists = []; // Get the message queue $messages = Factory::getApplication()->getMessageQueue(); diff --git a/libraries/src/Document/Renderer/Html/MetasRenderer.php b/libraries/src/Document/Renderer/Html/MetasRenderer.php index deb1a20cab183..b0720bc6601c0 100644 --- a/libraries/src/Document/Renderer/Html/MetasRenderer.php +++ b/libraries/src/Document/Renderer/Html/MetasRenderer.php @@ -25,6 +25,8 @@ */ class MetasRenderer extends DocumentRenderer { + use FixAssets; + /** * Renders the document metas and returns the results as a string * @@ -36,7 +38,7 @@ class MetasRenderer extends DocumentRenderer * * @since 4.0.0 */ - public function render($head, $params = array(), $content = null) + public function render($head, $params = [], $content = '') { // Convert the tagids to titles if (isset($this->_doc->_metaTags['name']['tags'])) @@ -72,22 +74,8 @@ public function render($head, $params = array(), $content = null) // Trigger the onBeforeCompileHead event $app->triggerEvent('onBeforeCompileHead'); - // Add Script Options as inline asset - $scriptOptions = $this->_doc->getScriptOptions(); - - if ($scriptOptions) - { - $prettyPrint = (JDEBUG && \defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : false); - $jsonOptions = json_encode($scriptOptions, $prettyPrint); - $jsonOptions = $jsonOptions ? $jsonOptions : '{}'; - - $wa->addInlineScript( - $jsonOptions, - ['name' => 'joomla.script.options', 'position' => 'before'], - ['type' => 'application/json', 'class' => 'joomla-script-options new'], - ['core'] - ); - } + // Fix any styles/scripts inserted using addCustomTag + $this->fixCustom(); // Lock the AssetManager $wa->lock(); @@ -209,6 +197,12 @@ public function render($head, $params = array(), $content = null) $buffer .= '>' . $lnEnd; } + // Output the custom tags - array_unique makes sure that we don't output the same tags twice + foreach ($this->_doc->_custom as $custom) + { + $buffer .= $tab . $custom . $lnEnd; + } + return ltrim($buffer, $tab); } } diff --git a/libraries/src/Document/Renderer/Html/ModuleRenderer.php b/libraries/src/Document/Renderer/Html/ModuleRenderer.php index 165595668b530..71d9538c2ee3b 100644 --- a/libraries/src/Document/Renderer/Html/ModuleRenderer.php +++ b/libraries/src/Document/Renderer/Html/ModuleRenderer.php @@ -22,18 +22,22 @@ */ class ModuleRenderer extends DocumentRenderer { + use FixAssets; + /** * Renders a module script and returns the results as a string * - * @param string $module The name of the module to render - * @param array $attribs Associative array of values - * @param string $content If present, module information from the buffer will be used + * @param string|object $module The name of the module to render + * @param array $attribs Associative array of values + * @param string $content If present, module information from the buffer will be used * * @return string The output of the script * + * @throws \Exception + * * @since 3.5 */ - public function render($module, $attribs = array(), $content = null) + public function render($module, $attribs = [], $content = '') { if (!\is_object($module)) { @@ -64,6 +68,14 @@ public function render($module, $attribs = array(), $content = null) // Set the module content if (!\is_null($content)) { + $app = Factory::getApplication(); + $template = $app->getTemplate(true); + + if ($template->params->getBool('joomla_skip_assets_processing_modules', true)) + { + $module->content = $this->fixAssets($content); + } + $module->content = $content; } @@ -73,25 +85,25 @@ public function render($module, $attribs = array(), $content = null) // Use parameters from template if (isset($attribs['params'])) { - $template_params = new Registry(html_entity_decode($attribs['params'], ENT_COMPAT, 'UTF-8')); - $params->merge($template_params); + $templateParams = new Registry(html_entity_decode($attribs['params'], ENT_COMPAT, 'UTF-8')); + $params->merge($templateParams); $module = clone $module; $module->params = (string) $params; } // Set cachemode parameter or use JModuleHelper::moduleCache from within the module instead - $cachemode = $params->get('cachemode', 'static'); + $cacheMode = $params->get('cachemode', 'static'); - if ($params->get('cache', 0) == 1 && Factory::getApplication()->get('caching') >= 1 && $cachemode !== 'id' && $cachemode !== 'safeuri') + if ($params->get('cache', 0) == 1 && Factory::getApplication()->get('caching') >= 1 && $cacheMode !== 'id' && $cacheMode !== 'safeuri') { // Default to itemid creating method and workarounds on - $cacheparams = new \stdClass; - $cacheparams->cachemode = $cachemode; - $cacheparams->class = ModuleHelper::class; - $cacheparams->method = 'renderModule'; - $cacheparams->methodparams = array($module, $attribs); + $cacheParams = new \stdClass; + $cacheParams->cachemode = $cacheMode; + $cacheParams->class = ModuleHelper::class; + $cacheParams->method = 'renderModule'; + $cacheParams->methodparams = array($module, $attribs); - return ModuleHelper::ModuleCache($module, $params, $cacheparams); + return ModuleHelper::ModuleCache($module, $params, $cacheParams); } return ModuleHelper::renderModule($module, $attribs); diff --git a/libraries/src/Document/Renderer/Html/ScriptsRenderer.php b/libraries/src/Document/Renderer/Html/ScriptsRenderer.php index e8fe01416a3a7..03944ee20098a 100644 --- a/libraries/src/Document/Renderer/Html/ScriptsRenderer.php +++ b/libraries/src/Document/Renderer/Html/ScriptsRenderer.php @@ -57,6 +57,21 @@ public function render($head, $params = array(), $content = null) // Merge with existing scripts, for rendering $assets = array_merge(array_values($assets), $this->_doc->_scripts); + // Add Script Options as inline asset + $scriptOptions = $this->_doc->getScriptOptions(); + + if ($scriptOptions) + { + $prettyPrint = (JDEBUG && \defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : false); + $jsonOptions = json_encode($scriptOptions, $prettyPrint); + $jsonOptions = $jsonOptions ? $jsonOptions : '{}'; + $nonce = $this->_doc->cspNonce ? ' nonce="' . $this->_doc->cspNonce . '"' : ''; + + $buffer .= ''; + } + + $buffer .= ''; + // Generate script file links foreach ($assets as $key => $item) { @@ -122,12 +137,6 @@ public function render($head, $params = array(), $content = null) } } - // Output the custom tags - array_unique makes sure that we don't output the same tags twice - foreach (array_unique($this->_doc->_custom) as $custom) - { - $buffer .= $tab . $custom . $lnEnd; - } - return ltrim($buffer, $tab); } @@ -154,14 +163,12 @@ private function renderElement($item) : string $lnEnd = $this->_doc->_getLineEnd(); $tab = $this->_doc->_getTab(); - $mediaVersion = $this->_doc->getMediaVersion(); // Get the attributes and other options if ($asset) { $attribs = $asset->getAttributes(); $version = $asset->getVersion(); - $conditional = $asset->getOption('conditional'); // Add an asset info for debugging if (JDEBUG) @@ -178,38 +185,25 @@ private function renderElement($item) : string { $attribs = $item; $version = isset($attribs['options']['version']) ? $attribs['options']['version'] : ''; - $conditional = !empty($attribs['options']['conditional']) ? $attribs['options']['conditional'] : null; } // To prevent double rendering $this->renderedSrc[$src] = true; - // Check if script uses media version. - if ($version && strpos($src, '?') === false && ($mediaVersion || $version !== 'auto')) - { - $src .= '?' . ($version === 'auto' ? $mediaVersion : $version); - } - - $buffer .= $tab; - - // This is for IE conditional statements support. - if (!\is_null($conditional)) - { - $buffer .= ''; - } - - $buffer .= $lnEnd; + // Check if script uses media version. +// if ($version && strpos($src, '?') === false && ($mediaVersion || $version !== 'auto')) +// { +// $src .= '?' . ($version === 'auto' ? $mediaVersion : $version); +// } +// +// // Render the element with attributes +// $buffer .= $tab . ''; +// +// $buffer .= $lnEnd; return $buffer; } @@ -225,10 +219,6 @@ private function renderElement($item) : string */ private function renderInlineElement($item) : string { - $buffer = ''; - $lnEnd = $this->_doc->_getLineEnd(); - $tab = $this->_doc->_getTab(); - if ($item instanceof WebAssetItemInterface) { $attribs = $item->getAttributes(); @@ -254,39 +244,26 @@ private function renderInlineElement($item) : string $attribs['nonce'] = $this->_doc->cspNonce; } - $buffer .= $tab . 'renderAttributes($attribs); - $buffer .= '>'; - - // This is for full XHTML support. - if ($this->_doc->_mime !== 'text/html') - { - $buffer .= $tab . $tab . '//renderAttributes($attribs, true); + $attribs['src'] = 'data:text/javascript;base64,' . base64_encode($content); + $content = ''; - $buffer .= $content; + $finalSrc = !empty($attribs['src']) ? ' src="' . $attribs['src'] . '"' : ''; - // See above note - if ($this->_doc->_mime !== 'text/html') - { - $buffer .= $tab . $tab . '//]]>' . $lnEnd; - } - - $buffer .= '' . $lnEnd; - - return $buffer; + return $this->_doc->_getTab() . '' . $this->_doc->_getLineEnd(); } /** * Renders the element attributes * - * @param array $attributes The element attributes + * @param array $attributes The element attributes + * @param bool $forceDefer Force the defer attribute * * @return string The attributes string * * @since 4.0.0 */ - private function renderAttributes(array $attributes) : string + private function renderAttributes(array $attributes, bool $forceDefer) : string { $buffer = ''; @@ -336,6 +313,108 @@ private function renderAttributes(array $attributes) : string } } + if ($forceDefer && !isset($attributes['async']) && !isset($attributes['defer'])) + { + $buffer .= ' defer'; + } + return $buffer; } + + /** + * @param string $src The source string + * + * @return string|string[] + */ + public function checkEsAlternative(string $src, $attribs, $version) + { + $mediaVersion = $this->_doc->getMediaVersion(); + + if (strpos('http://', $src) || strpos('https://', $src) || strpos('//', $src)) + { + return ''; + } + + $testx = ''; + + // The given file IS ES6 + if (strpos('.es6.', $src)) + { + if (!strpos('.min.js', $src)) + { + $newSrc = str_replace('.es6.js', '.js', $src); + } + else + { + $newSrc = str_replace('.es6.min.js', '.min.js', $src); + } + + if (!empty($newSrc) && is_file(JPATH_ROOT . '/' . $newSrc)) + { + // Check if script uses media version. + if ($version && strpos($src, '?') === false && ($mediaVersion || $version !== 'auto')) + { + $newSrc .= '?' . ($version === 'auto' ? $mediaVersion : $version); + } + + $attribs['nomodule'] = true; + + // Render the element with attributes + $testx = ''; + } + } + + // The given file IS ES5 + if (!strpos($src, '.es6.')) + { + if (!strpos($src, '.min.')) + { + $newSrc = str_replace('.js', '.es6.js', $src); + } + else + { + $newSrc = str_replace('.min.js', '.es6.min.js', $src); + } + + if (!empty($newSrc) && is_file(JPATH_ROOT . $newSrc)) + { + // Check if script uses media version. + if ($version && strpos($newSrc, '?') === false && ($mediaVersion || $version !== 'auto')) + { + $newSrc .= '?' . ($version === 'auto' ? $mediaVersion : $version); + } + + $attribs['type'] = 'module'; + + // Render the element with attributes + $testx .= ''; + } + + $noModule = ''; + if (isset($attribs['type'])) + { + unset($attribs['type']); + $noModule = ' nomodule'; + } + + + // Check if script uses media version. + if ($version && strpos($src, '?') === false && ($mediaVersion || $version !== 'auto')) + { + $src .= '?' . ($version === 'auto' ? $mediaVersion : $version); + } + + // Render the element with attributes + $testx .= ''; + + } + + return $testx; + } } diff --git a/libraries/src/Document/Renderer/Html/StylesRenderer.php b/libraries/src/Document/Renderer/Html/StylesRenderer.php index c130dcc8b5e75..46c5580bdf196 100644 --- a/libraries/src/Document/Renderer/Html/StylesRenderer.php +++ b/libraries/src/Document/Renderer/Html/StylesRenderer.php @@ -152,7 +152,6 @@ private function renderElement($item) : string { $attribs = $asset->getAttributes(); $version = $asset->getVersion(); - $conditional = $asset->getOption('conditional'); // Add an asset info for debugging if (JDEBUG) @@ -169,7 +168,6 @@ private function renderElement($item) : string { $attribs = $item; $version = isset($attribs['options']['version']) ? $attribs['options']['version'] : ''; - $conditional = !empty($attribs['options']['conditional']) ? $attribs['options']['conditional'] : null; } // To prevent double rendering @@ -183,12 +181,6 @@ private function renderElement($item) : string $buffer .= $tab; - // This is for IE conditional statements support. - if (!\is_null($conditional)) - { - $buffer .= ''; - } - $buffer .= $lnEnd; return $buffer; diff --git a/libraries/src/HTML/HTMLHelper.php b/libraries/src/HTML/HTMLHelper.php index 59f863b34591c..be1e0c1707feb 100644 --- a/libraries/src/HTML/HTMLHelper.php +++ b/libraries/src/HTML/HTMLHelper.php @@ -782,7 +782,7 @@ public static function stylesheet($file, $options = array(), $attribs = array()) { if (\count($includes) === 0) { - return; + return null; } if (\count($includes) === 1) diff --git a/plugins/system/debug/debug.php b/plugins/system/debug/debug.php index 279740af54b72..c7cab23767aca 100644 --- a/plugins/system/debug/debug.php +++ b/plugins/system/debug/debug.php @@ -206,7 +206,7 @@ public function onAfterDispatch() 'plg_system_debug/debug.min.js', [], ['defer' => true], - ['jquery'] + ['jquery', 'jquery-noconflict'] ); } @@ -343,7 +343,7 @@ public function onAfterRespond() return; } - echo str_replace('', $debugBarRenderer->renderHead() . $debugBarRenderer->render() . '', $contents); + echo str_replace('', $debugBarRenderer->renderHead() . $debugBarRenderer->render() . '', $contents); } /** diff --git a/plugins/system/debug/src/JavascriptRenderer.php b/plugins/system/debug/src/JavascriptRenderer.php index 65e314baa8f99..d35417263af3b 100644 --- a/plugins/system/debug/src/JavascriptRenderer.php +++ b/plugins/system/debug/src/JavascriptRenderer.php @@ -66,7 +66,7 @@ public function renderHead() foreach ($jsFiles as $file) { - $html .= sprintf('' . "\n", $file); + $html .= sprintf('' . "\n", $file); } $nonce = ''; @@ -78,7 +78,7 @@ public function renderHead() foreach ($inlineJs as $content) { - $html .= sprintf('' . "\n", $nonce, $content); + $html .= '' . "\n"; } foreach ($inlineHead as $content) @@ -120,22 +120,60 @@ public function render($initialize = true, $renderStackedData = true) } $suffix = !$initialize ? '(ajax)' : null; - $js .= $this->getAddDatasetCode($this->debugBar->getCurrentRequestId(), $this->debugBar->getData(), $suffix); - - $nonce = ''; + $data = $this->getAddDatasetCode($this->debugBar->getCurrentRequestId(), $this->debugBar->getData(), $suffix); + $js .= $data->inlineJs; + $nonce = ''; if ($doc->cspNonce) { - $nonce = ' nonce="' . $doc->cspNonce . '"'; + $nonce = 'nonce="' . $doc->cspNonce . '"'; } if ($this->useRequireJs) { - return "\n"; + return $data->jsonTag . "\n" . '' . "\n"; } else { - return "\n"; + return $data->jsonTag . "\n" . '' . "\n"; } } + + /** + * Returns the js code needed to add a dataset + * + * @param string $requestId + * @param array $data + * @param mixed $suffix + * @return string + */ + protected function getAddDatasetCode($requestId, $data, $suffix = null) + { + $output = new \stdClass(); + $finalVar = '"' . $requestId . ($suffix ? ", " . json_encode($suffix) : '') . '"'; + + $output->jsonTag = ''; + $output->inlineJs = << 'module'], + [], ['skipto'] ); }