Skip to content

Commit

Permalink
[FEATURE] Support directive image with target
Browse files Browse the repository at this point in the history
resolves #911
  • Loading branch information
linawolf authored and jaapio committed Mar 9, 2024
1 parent c429f6f commit a3508e2
Show file tree
Hide file tree
Showing 11 changed files with 611 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,21 @@
namespace phpDocumentor\Guides\RestructuredText\Directives;

use phpDocumentor\Guides\Nodes\ImageNode;
use phpDocumentor\Guides\Nodes\Inline\DocReferenceNode;
use phpDocumentor\Guides\Nodes\Inline\HyperLinkNode;
use phpDocumentor\Guides\Nodes\Inline\LinkInlineNode;
use phpDocumentor\Guides\Nodes\Inline\ReferenceNode;
use phpDocumentor\Guides\Nodes\Node;
use phpDocumentor\Guides\ReferenceResolvers\DocumentNameResolverInterface;
use phpDocumentor\Guides\RestructuredText\Parser\BlockContext;
use phpDocumentor\Guides\RestructuredText\Parser\Directive;

use function dirname;
use function filter_var;
use function preg_match;

use const FILTER_VALIDATE_EMAIL;
use const FILTER_VALIDATE_URL;

/**
* Renders an image, example :
Expand All @@ -30,6 +39,12 @@
*/
final class ImageDirective extends BaseDirective
{
/** @see https://regex101.com/r/9dUrzu/3 */
public const REFERENCE_REGEX = '/^([a-zA-Z0-9-_]+)_$/';

/** @see https://regex101.com/r/6vPoiA/2 */
public const REFERENCE_ESCAPED_REGEX = '/^`([^`]+)`_$/';

public function __construct(
private readonly DocumentNameResolverInterface $documentNameResolver,
) {
Expand All @@ -45,11 +60,38 @@ public function processNode(
BlockContext $blockContext,
Directive $directive,
): Node {
return new ImageNode(
$node = new ImageNode(
$this->documentNameResolver->absoluteUrl(
dirname($blockContext->getDocumentParserContext()->getContext()->getCurrentAbsolutePath()),
$directive->getData(),
),
);
if ($directive->hasOption('target')) {
$targetReference = (string) $directive->getOption('target')->getValue();
$node->setTarget($this->resolveLinkTarget($targetReference));
}

return $node;
}

private function resolveLinkTarget(string $targetReference): LinkInlineNode
{
if (filter_var($targetReference, FILTER_VALIDATE_EMAIL)) {
return new HyperLinkNode('', $targetReference);
}

if (filter_var($targetReference, FILTER_VALIDATE_URL)) {
return new HyperLinkNode('', $targetReference);
}

if (preg_match(self::REFERENCE_REGEX, $targetReference, $matches)) {
return new ReferenceNode($matches[1], '');
}

if (preg_match(self::REFERENCE_ESCAPED_REGEX, $targetReference, $matches)) {
return new ReferenceNode($matches[1], '');
}

return new DocReferenceNode($targetReference, '');
}
}
3 changes: 3 additions & 0 deletions packages/guides/resources/config/guides.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use phpDocumentor\Guides\ReferenceResolvers\DocumentNameResolverInterface;
use phpDocumentor\Guides\ReferenceResolvers\EmailReferenceResolver;
use phpDocumentor\Guides\ReferenceResolvers\ExternalReferenceResolver;
use phpDocumentor\Guides\ReferenceResolvers\ImageReferenceResolverPreRender;
use phpDocumentor\Guides\ReferenceResolvers\Interlink\DefaultInventoryLoader;
use phpDocumentor\Guides\ReferenceResolvers\Interlink\DefaultInventoryRepository;
use phpDocumentor\Guides\ReferenceResolvers\Interlink\InventoryLoader;
Expand Down Expand Up @@ -192,6 +193,8 @@

->set(ReferenceResolverPreRender::class)
->tag('phpdoc.guides.prerenderer')
->set(ImageReferenceResolverPreRender::class)
->tag('phpdoc.guides.prerenderer')

->set(InMemoryRendererFactory::class)
->arg('$renderSets', tagged_iterator('phpdoc.renderer.typerenderer', 'format'))
Expand Down
2 changes: 2 additions & 0 deletions packages/guides/resources/template/html/body/image.html.twig
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{% if node.target %}<a href="{{ node.target.url }}">{% endif %}
<img
src="{%- if node.value is external_target -%} {{ node.value }} {%- else -%} {{ asset(node.value) }} {%- endif -%}"
{% if node.hasOption('width') %}width="{{ node.option('width') }}"{% endif%}
Expand All @@ -7,3 +8,4 @@
{% if node.hasOption('title') %}title="{{ node.option('title') }}"{% endif%}
{% if node.classesString %}class="{{ node.classesString }}"{% endif%}
/>
{% if node.target %}</a>{% endif %}
13 changes: 13 additions & 0 deletions packages/guides/src/Nodes/ImageNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,19 @@

namespace phpDocumentor\Guides\Nodes;

use phpDocumentor\Guides\Nodes\Inline\LinkInlineNode;

final class ImageNode extends TextNode
{
public LinkInlineNode|null $target = null;

public function getTarget(): LinkInlineNode|null
{
return $this->target;
}

public function setTarget(LinkInlineNode|null $target): void
{
$this->target = $target;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

declare(strict_types=1);

/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/

namespace phpDocumentor\Guides\ReferenceResolvers;

use phpDocumentor\Guides\NodeRenderers\PreRenderers\PreNodeRenderer;
use phpDocumentor\Guides\Nodes\ImageNode;
use phpDocumentor\Guides\Nodes\Node;
use phpDocumentor\Guides\RenderContext;
use Psr\Log\LoggerInterface;
use Webmozart\Assert\Assert;

use function array_merge;
use function sprintf;

final class ImageReferenceResolverPreRender implements PreNodeRenderer
{
public function __construct(
private readonly DelegatingReferenceResolver $referenceResolver,
private readonly LoggerInterface $logger,
) {
}

public function supports(Node $node): bool
{
return $node instanceof ImageNode;
}

public function execute(Node $node, RenderContext $renderContext): Node
{
Assert::isInstanceOf($node, ImageNode::class);
if ($node->getTarget() === null) {
return $node;
}

$referenceLinkNode = $node->getTarget();
$messages = new Messages();
$resolved = $this->referenceResolver->resolve($referenceLinkNode, $renderContext, $messages);
if (!$resolved) {
$this->logger->warning(
$messages->getLastWarning()?->getMessage() ?? sprintf(
'Target %s of image could not be resolved in %s',
$referenceLinkNode->getTargetReference(),
$renderContext->getCurrentFileName(),
),
array_merge($renderContext->getLoggerInformation(), $messages->getLastWarning()?->getDebugInfo() ?? []),
);
}

return $node;
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit a3508e2

Please sign in to comment.