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 <bot@styleci.io>
This commit is contained in:
Daniël Klabbers 2022-06-21 17:32:23 +02:00 committed by GitHub
parent 62be3e01be
commit 0859bb13a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 87 additions and 4 deletions

View File

@ -0,0 +1,62 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Extend;
use Flarum\Extension\Extension;
use Flarum\Foundation\Config;
use Illuminate\Contracts\Container\Container;
use Laminas\Diactoros\Uri;
use s9e\TextFormatter\Renderer;
use s9e\TextFormatter\Utils;
class Link implements ExtenderInterface
{
protected $setRel = null;
protected $setTarget = null;
public function setRel(callable $callable): static
{
$this->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);
}
}

View File

@ -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;
});
}
}