From 0859bb13a593403d57e5ded79e47fbb1e08ed85c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20Klabbers?= Date: Tue, 21 Jun 2022 17:32:23 +0200 Subject: [PATCH] feature: adds advanced link handling in core (#3455) * feature: adds advanced link handling in core This PR adds rel and target to textformatter so that these can be easily extended and rendered into the source. Without using the Extender the default values `ngc nofollow` are provided as a backward compatible way. The new extender allows conditional overrides, a proof of concept extension is available at https://github.com/luceos/flarum-ext-dofollow; I will probably migrate this into the Blomstra namespace soon. * Apply fixes from StyleCI * fix typehints * fix: mixed typehint is php 8+ Co-authored-by: StyleCI Bot --- framework/core/src/Extend/Link.php | 62 ++++++++++++++++++++++ framework/core/src/Formatter/Formatter.php | 29 ++++++++-- 2 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 framework/core/src/Extend/Link.php diff --git a/framework/core/src/Extend/Link.php b/framework/core/src/Extend/Link.php new file mode 100644 index 000000000..b9c484414 --- /dev/null +++ b/framework/core/src/Extend/Link.php @@ -0,0 +1,62 @@ +setRel = $callable; + + return $this; + } + + public function setTarget(callable $callable): static + { + $this->setTarget = $callable; + + return $this; + } + + public function extend(Container $container, Extension $extension = null) + { + $siteUrl = $container->make(Config::class)->url(); + + (new Formatter)->render(function (Renderer $renderer, $context, string $xml) use ($siteUrl) { + return Utils::replaceAttributes($xml, 'URL', function ($attributes) use ($siteUrl) { + $uri = isset($attributes['url']) + ? new Uri($attributes['url']) + : null; + + $setRel = $this->setRel; + if ($setRel && $rel = $setRel($uri, $siteUrl, $attributes)) { + $attributes['rel'] = $rel; + } + + $setTarget = $this->setTarget; + if ($setTarget && $target = $setTarget($uri, $siteUrl, $attributes)) { + $attributes['target'] = $target; + } + + return $attributes; + }); + })->extend($container); + } +} diff --git a/framework/core/src/Formatter/Formatter.php b/framework/core/src/Formatter/Formatter.php index d2396ea27..7cd872401 100644 --- a/framework/core/src/Formatter/Formatter.php +++ b/framework/core/src/Formatter/Formatter.php @@ -9,10 +9,14 @@ namespace Flarum\Formatter; +use DOMDocument; +use DOMElement; use Illuminate\Contracts\Cache\Repository; use Psr\Http\Message\ServerRequestInterface; use s9e\TextFormatter\Configurator; +use s9e\TextFormatter\Renderer; use s9e\TextFormatter\Unparser; +use s9e\TextFormatter\Utils; class Formatter { @@ -98,7 +102,7 @@ class Formatter * Render parsed XML. * * @param string $xml - * @param mixed $context + * @param mixed|null $context * @param ServerRequestInterface|null $request * @return string */ @@ -110,6 +114,8 @@ class Formatter $xml = $callback($renderer, $context, $xml, $request); } + $xml = $this->configureDefaultsOnLinks($renderer, $xml, $context, $request); + return $renderer->render($xml); } @@ -174,11 +180,13 @@ class Formatter */ protected function configureExternalLinks(Configurator $configurator) { + /** @var DOMDocument $dom */ $dom = $configurator->tags['URL']->template->asDOM(); + /** @var DOMElement $a */ foreach ($dom->getElementsByTagName('a') as $a) { - $rel = $a->getAttribute('rel'); - $a->setAttribute('rel', "$rel nofollow ugc"); + $a->prependXslCopyOf('@target'); + $a->prependXslCopyOf('@rel'); } $dom->saveChanges(); @@ -217,7 +225,7 @@ class Formatter /** * Get the renderer. * - * @return \s9e\TextFormatter\Renderer + * @return Renderer */ protected function getRenderer() { @@ -239,4 +247,17 @@ class Formatter { return $this->getComponent('js'); } + + protected function configureDefaultsOnLinks( + Renderer $renderer, + string $xml, + $context = null, + ServerRequestInterface $request = null + ): string { + return Utils::replaceAttributes($xml, 'URL', function ($attributes) { + $attributes['rel'] = $attributes['rel'] ?? 'ugc nofollow'; + + return $attributes; + }); + } }