diff --git a/CHANGELOG.md b/CHANGELOG.md index c830c70e5..3b5a5635c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ 1. [](#new) * Added links and modules support to `HtmlBlock` class + * Added module support for twig script tag: `{% script module 'theme://js/module.mjs' %}` # v1.7.27.1 ## 01/12/2022 diff --git a/system/src/Grav/Common/Twig/Node/TwigNodeScript.php b/system/src/Grav/Common/Twig/Node/TwigNodeScript.php index d7b4ae79f..7a665b78c 100644 --- a/system/src/Grav/Common/Twig/Node/TwigNodeScript.php +++ b/system/src/Grav/Common/Twig/Node/TwigNodeScript.php @@ -27,6 +27,7 @@ class TwigNodeScript extends Node implements NodeCaptureInterface /** * TwigNodeScript constructor. * @param Node|null $body + * @param string|null $type * @param AbstractExpression|null $file * @param AbstractExpression|null $group * @param AbstractExpression|null $priority @@ -34,12 +35,12 @@ class TwigNodeScript extends Node implements NodeCaptureInterface * @param int $lineno * @param string|null $tag */ - public function __construct(?Node $body, ?AbstractExpression $file, ?AbstractExpression $group, ?AbstractExpression $priority, ?AbstractExpression $attributes, $lineno = 0, $tag = null) + public function __construct(?Node $body, ?string $type, ?AbstractExpression $file, ?AbstractExpression $group, ?AbstractExpression $priority, ?AbstractExpression $attributes, $lineno = 0, $tag = null) { $nodes = ['body' => $body, 'file' => $file, 'group' => $group, 'priority' => $priority, 'attributes' => $attributes]; $nodes = array_filter($nodes); - parent::__construct($nodes, [], $lineno, $tag); + parent::__construct($nodes, ['type' => $type], $lineno, $tag); } /** @@ -90,7 +91,8 @@ class TwigNodeScript extends Node implements NodeCaptureInterface if ($this->hasNode('file')) { $compiler - ->write('$assets->addJs(') + ->write("\$method = '{$this->getAttribute('type')}' === 'module' ? 'addJsModule' : 'addJs';\n") + ->write('$assets->{$method}(') ->subcompile($this->getNode('file')) ->raw(", \$attributes);\n"); } else { @@ -98,7 +100,8 @@ class TwigNodeScript extends Node implements NodeCaptureInterface ->write("ob_start();\n") ->subcompile($this->getNode('body')) ->write('$content = ob_get_clean();' . "\n") - ->write("\$assets->addInlineJs(\$content, \$attributes);\n"); + ->write("\$method = '{$this->getAttribute('type')}' === 'module' ? 'addInlineJsModule' : 'addInlineJs';\n") + ->write("\$assets->{\$method}(\$content, \$attributes);\n"); } } } diff --git a/system/src/Grav/Common/Twig/TokenParser/TwigTokenParserScript.php b/system/src/Grav/Common/Twig/TokenParser/TwigTokenParserScript.php index e98365b94..b943a2540 100644 --- a/system/src/Grav/Common/Twig/TokenParser/TwigTokenParserScript.php +++ b/system/src/Grav/Common/Twig/TokenParser/TwigTokenParserScript.php @@ -15,14 +15,20 @@ use Twig\Token; use Twig\TokenParser\AbstractTokenParser; /** - * Adds a script to head/bottom/custom location in the document. + * Adds a script to head/bottom/custom group location in the document. * - * {% script 'theme://js/something.js' at 'bottom' priority: 20 with { defer: true, async: true } %} + * {% script 'theme://js/something.js' at 'bottom' priority: 20 with { position: 'pipeline', loading: 'async defer' } %} + * {% script module 'theme://js/module.mjs' at 'head' %} * + * {% script 'theme://js/something.js' at 'bottom' priority: 20 with { loading: 'inline' } %} * {% script at 'bottom' priority: 20 %} - * alert('Warning!'); + * alert('Warning!'); + * {% endscript %} + * + * {% script module 'theme://js/module.mjs' at 'bottom' with { loading: 'inline' } %} + * {% script module at 'bottom' %} + * ... * {% endscript %} - */ class TwigTokenParserScript extends AbstractTokenParser { @@ -38,7 +44,7 @@ class TwigTokenParserScript extends AbstractTokenParser $lineno = $token->getLine(); $stream = $this->parser->getStream(); - [$file, $group, $priority, $attributes] = $this->parseArguments($token); + [$type, $file, $group, $priority, $attributes] = $this->parseArguments($token); $content = null; if ($file === null) { @@ -46,7 +52,7 @@ class TwigTokenParserScript extends AbstractTokenParser $stream->expect(Token::BLOCK_END_TYPE); } - return new TwigNodeScript($content, $file, $group, $priority, $attributes, $lineno, $this->getTag()); + return new TwigNodeScript($content, $type, $file, $group, $priority, $attributes, $lineno, $this->getTag()); } /** @@ -73,6 +79,12 @@ class TwigTokenParserScript extends AbstractTokenParser } while (true); } + $type = null; + if ($stream->test(Token::NAME_TYPE, 'module')) { + $type = $stream->getCurrent()->getValue(); + $stream->next(); + } + $file = null; if (!$stream->test(Token::NAME_TYPE) && !$stream->test(Token::OPERATOR_TYPE, 'in') && !$stream->test(Token::BLOCK_END_TYPE)) { $file = $this->parser->getExpressionParser()->parseExpression(); @@ -96,7 +108,7 @@ class TwigTokenParserScript extends AbstractTokenParser $stream->expect(Token::BLOCK_END_TYPE); - return [$file, $group, $priority, $attributes]; + return [$type, $file, $group, $priority, $attributes]; } /**