Added twig tag for links: {% link icon 'theme://images/favicon.png' priority: 20 with { type: 'image/png' } %}

This commit is contained in:
Matias Griese
2022-01-13 13:06:19 +02:00
parent 1ab2f7083c
commit da6b41f8a6
4 changed files with 210 additions and 0 deletions

View File

@@ -4,6 +4,7 @@
1. [](#new)
* Added links and modules support to `HtmlBlock` class
* Added module support for twig script tag: `{% script module 'theme://js/module.mjs' %}`
* Added twig tag for links: `{% link icon 'theme://images/favicon.png' priority: 20 with { type: 'image/png' } %}`
# v1.7.27.1
## 01/12/2022

View File

@@ -22,6 +22,7 @@ use Grav\Common\Page\Media;
use Grav\Common\Scheduler\Cron;
use Grav\Common\Security;
use Grav\Common\Twig\TokenParser\TwigTokenParserCache;
use Grav\Common\Twig\TokenParser\TwigTokenParserLink;
use Grav\Common\Twig\TokenParser\TwigTokenParserRender;
use Grav\Common\Twig\TokenParser\TwigTokenParserScript;
use Grav\Common\Twig\TokenParser\TwigTokenParserStyle;
@@ -252,6 +253,7 @@ class GravExtension extends AbstractExtension implements GlobalsInterface
new TwigTokenParserTryCatch(),
new TwigTokenParserScript(),
new TwigTokenParserStyle(),
new TwigTokenParserLink(),
new TwigTokenParserMarkdown(),
new TwigTokenParserSwitch(),
new TwigTokenParserCache(),

View File

@@ -0,0 +1,98 @@
<?php
/**
* @package Grav\Common\Twig
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Common\Twig\Node;
use LogicException;
use Twig\Compiler;
use Twig\Node\Expression\AbstractExpression;
use Twig\Node\Node;
use Twig\Node\NodeCaptureInterface;
/**
* Class TwigNodeLink
* @package Grav\Common\Twig\Node
*/
class TwigNodeLink extends Node implements NodeCaptureInterface
{
/** @var string */
protected $tagName = 'link';
/**
* TwigNodeLink constructor.
* @param string|null $rel
* @param AbstractExpression|null $file
* @param AbstractExpression|null $group
* @param AbstractExpression|null $priority
* @param AbstractExpression|null $attributes
* @param int $lineno
* @param string|null $tag
*/
public function __construct(?string $rel, ?AbstractExpression $file, ?AbstractExpression $group, ?AbstractExpression $priority, ?AbstractExpression $attributes, $lineno = 0, $tag = null)
{
$nodes = ['file' => $file, 'group' => $group, 'priority' => $priority, 'attributes' => $attributes];
$nodes = array_filter($nodes);
parent::__construct($nodes, ['rel' => $rel], $lineno, $tag);
}
/**
* Compiles the node to PHP.
*
* @param Compiler $compiler A Twig Compiler instance
* @return void
* @throws LogicException
*/
public function compile(Compiler $compiler): void
{
$compiler->addDebugInfo($this);
if (!$this->hasNode('file')) {
return;
}
$compiler->write("\$assets = \\Grav\\Common\\Grav::instance()['assets'];\n");
$compiler->write('$attributes = [\'rel\' => \'' . $this->getAttribute('rel') . '\'];' . "\n");
if ($this->hasNode('attributes')) {
$compiler
->write('$attributes += ')
->subcompile($this->getNode('attributes'))
->raw(";\n")
->write("if (!is_array(\$attributes)) {\n")
->indent()
->write("throw new UnexpectedValueException('{% {$this->tagName} with x %}: x is not an array');\n")
->outdent()
->write("}\n");
}
if ($this->hasNode('group')) {
$compiler
->write("\$attributes['group'] = ")
->subcompile($this->getNode('group'))
->raw(";\n")
->write("if (!is_string(\$attributes['group'])) {\n")
->indent()
->write("throw new UnexpectedValueException('{% {$this->tagName} in x %}: x is not a string');\n")
->outdent()
->write("}\n");
}
if ($this->hasNode('priority')) {
$compiler
->write("\$attributes['priority'] = (int)(")
->subcompile($this->getNode('priority'))
->raw(");\n");
}
$compiler
->write('$assets->addLink(')
->subcompile($this->getNode('file'))
->raw(", \$attributes);\n");
}
}

View File

@@ -0,0 +1,109 @@
<?php
/**
* @package Grav\Common\Twig
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Common\Twig\TokenParser;
use Grav\Common\Twig\Node\TwigNodeLink;
use Twig\Error\SyntaxError;
use Twig\Token;
use Twig\TokenParser\AbstractTokenParser;
/**
* Adds a link to the document. First parameter is always value of `rel` without quotes.
*
* {% link icon 'theme://images/favicon.png' priority: 20 with { type: 'image/png' } %}
* {% link modulepreload 'plugin://grav-plugin/build/js/vendor.js' %}
*/
class TwigTokenParserLink extends AbstractTokenParser
{
protected $rel = [
'alternate',
'author',
'dns-prefetch',
'help',
'icon',
'license',
'next',
'pingback',
'preconnect',
'prefetch',
'preload',
'prerender',
'prev',
'search',
'stylesheet',
];
/**
* Parses a token and returns a node.
*
* @param Token $token
* @return TwigNodeLink
* @throws SyntaxError
*/
public function parse(Token $token)
{
$lineno = $token->getLine();
[$rel, $file, $group, $priority, $attributes] = $this->parseArguments($token);
return new TwigNodeLink($rel, $file, $group, $priority, $attributes, $lineno, $this->getTag());
}
/**
* @param Token $token
* @return array
*/
protected function parseArguments(Token $token): array
{
$stream = $this->parser->getStream();
$rel = null;
if ($stream->test(Token::NAME_TYPE, $this->rel)) {
$rel = $stream->getCurrent()->getValue();
$stream->next();
}
$file = null;
if (!$stream->test(Token::NAME_TYPE) && !$stream->test(Token::BLOCK_END_TYPE)) {
$file = $this->parser->getExpressionParser()->parseExpression();
}
$group = null;
if ($stream->nextIf(Token::NAME_TYPE, 'at')) {
$group = $this->parser->getExpressionParser()->parseExpression();
}
$priority = null;
if ($stream->nextIf(Token::NAME_TYPE, 'priority')) {
$stream->expect(Token::PUNCTUATION_TYPE, ':');
$priority = $this->parser->getExpressionParser()->parseExpression();
}
$attributes = null;
if ($stream->nextIf(Token::NAME_TYPE, 'with')) {
$attributes = $this->parser->getExpressionParser()->parseExpression();
}
$stream->expect(Token::BLOCK_END_TYPE);
return [$rel, $file, $group, $priority, $attributes];
}
/**
* Gets the tag name associated with this token parser.
*
* @return string The tag name
*/
public function getTag(): string
{
return 'link';
}
}