feat(OC/Template): Add type="module" for ES6 scripts

Signed-off-by: Ferdinand Thiessen <rpm@fthiessen.de>
This commit is contained in:
Ferdinand Thiessen
2023-01-10 01:40:42 +01:00
parent 00e041b907
commit b642137c65
2 changed files with 40 additions and 5 deletions

View File

@@ -72,14 +72,19 @@ function emit_css_loading_tags($obj) {
* Prints a <script> tag with nonce and defer depending on config
* @param string $src the source URL, ignored when empty
* @param string $script_content the inline script content, ignored when empty
* @param string $content_type the type of the source (e.g. 'module')
*/
function emit_script_tag($src, $script_content = '') {
function emit_script_tag(string $src, string $script_content = '', string $content_type = '') {
$nonceManager = \OC::$server->get(\OC\Security\CSP\ContentSecurityPolicyNonceManager::class);
$defer_str = ' defer';
$s = '<script nonce="' . \OC::$server->getContentSecurityPolicyNonceManager()->getNonce() . '"';
$type = $content_type !== '' ? ' type="' . $content_type . '"' : '';
$s = '<script nonce="' . $nonceManager->getNonce() . '"';
if (!empty($src)) {
// emit script tag for deferred loading from $src
$s .= $defer_str.' src="' . $src .'">';
} elseif (!empty($script_content)) {
$s .= $defer_str.' src="' . $src .'"' . $type . '>';
} elseif ($script_content !== '') {
// emit script tag for inline script from $script_content without defer (see MDN)
$s .= ">\n".$script_content."\n";
} else {
@@ -96,7 +101,8 @@ function emit_script_tag($src, $script_content = '') {
*/
function emit_script_loading_tags($obj) {
foreach ($obj['jsfiles'] as $jsfile) {
emit_script_tag($jsfile, '');
$type = str_ends_with($jsfile, '.mjs') ? 'module' : '';
emit_script_tag($jsfile, '', $type);
}
if (!empty($obj['inline_ocjs'])) {
emit_script_tag('', $obj['inline_ocjs']);

View File

@@ -57,6 +57,35 @@ class TemplateFunctionsTest extends \Test\TestCase {
print_unescaped($string);
}
public function testEmitScriptTagWithContent() {
$this->expectOutputRegex('/<script nonce="[^"]+">\nalert\(\)\n<\/script>\n?/');
emit_script_tag('', 'alert()');
}
public function testEmitScriptTagWithSource() {
$this->expectOutputRegex('/<script nonce=".*" defer src="some.js"><\/script>/');
emit_script_tag('some.js');
}
public function testEmitScriptTagWithModuleSource() {
$this->expectOutputRegex('/<script nonce=".*" defer src="some.mjs" type="module"><\/script>/');
emit_script_tag('some.mjs', '', 'module');
}
public function testEmitScriptLoadingTags() {
// Test mjs js and inline content
$pattern = '/src="some\.mjs"[^>]+type="module"[^>]*>.+\n'; // some.mjs with type = module
$pattern .= '<script[^>]+src="other\.js"[^>]*>.+\n'; // other.js as plain javascript
$pattern .= '<script[^>]*>\n?.*inline.*\n?<\/script>'; // inline content
$pattern .= '/'; // no flags
$this->expectOutputRegex($pattern);
emit_script_loading_tags([
'jsfiles' => ['some.mjs', 'other.js'],
'inline_ocjs' => '// inline'
]);
}
// ---------------------------------------------------------------------------
// Test relative_modified_date with dates only
// ---------------------------------------------------------------------------