mirror of
https://github.com/erusev/parsedown.git
synced 2023-08-10 21:13:06 +03:00
Implement Link
This commit is contained in:
parent
79a38a1ebb
commit
dad0088adb
128
src/Components/Inlines/Link.php
Normal file
128
src/Components/Inlines/Link.php
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Erusev\Parsedown\Components\Inlines;
|
||||||
|
|
||||||
|
use Erusev\Parsedown\AST\Handler;
|
||||||
|
use Erusev\Parsedown\AST\StateRenderable;
|
||||||
|
use Erusev\Parsedown\Components\Inline;
|
||||||
|
use Erusev\Parsedown\Configurables\DefinitionBook;
|
||||||
|
use Erusev\Parsedown\Configurables\SafeMode;
|
||||||
|
use Erusev\Parsedown\Html\Renderables\Element;
|
||||||
|
use Erusev\Parsedown\Html\Renderables\Text;
|
||||||
|
use Erusev\Parsedown\Parsedown;
|
||||||
|
use Erusev\Parsedown\Parsing\Excerpt;
|
||||||
|
use Erusev\Parsedown\State;
|
||||||
|
|
||||||
|
/** @psalm-type _Metadata=array{href: string, title?: string} */
|
||||||
|
final class Link implements Inline
|
||||||
|
{
|
||||||
|
use WidthTrait, DefaultBeginPosition;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $label;
|
||||||
|
|
||||||
|
/** @var _Metadata */
|
||||||
|
private $attributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $label
|
||||||
|
* @param _Metadata $attributes
|
||||||
|
* @param int $width
|
||||||
|
*/
|
||||||
|
public function __construct($label, $attributes, $width)
|
||||||
|
{
|
||||||
|
$this->label = $label;
|
||||||
|
$this->attributes = $attributes;
|
||||||
|
$this->width = $width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Excerpt $Excerpt
|
||||||
|
* @param State $State
|
||||||
|
* @return static|null
|
||||||
|
*/
|
||||||
|
public static function build(Excerpt $Excerpt, State $State)
|
||||||
|
{
|
||||||
|
$remainder = $Excerpt->text();
|
||||||
|
|
||||||
|
if (! \preg_match('/\[((?:[^][]++|(?R))*+)\]/', $remainder, $matches)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$rawLabelPart = $matches[0];
|
||||||
|
$label = $matches[1];
|
||||||
|
/** @var _Metadata|null */
|
||||||
|
$attributes = null;
|
||||||
|
|
||||||
|
$extent = \strlen($matches[0]);
|
||||||
|
|
||||||
|
$remainder = \substr($remainder, $extent);
|
||||||
|
|
||||||
|
if (\preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*+"|\'[^\']*+\'))?\s*+[)]/', $remainder, $matches)) {
|
||||||
|
$attributes = ['href' => $matches[1]];
|
||||||
|
|
||||||
|
if (isset($matches[2])) {
|
||||||
|
$attributes['title'] = \substr($matches[2], 1, - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$extent += \strlen($matches[0]);
|
||||||
|
} else {
|
||||||
|
if (\preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) {
|
||||||
|
$definition = \strlen($matches[1]) ? $matches[1] : $label;
|
||||||
|
$definition = \strtolower($definition);
|
||||||
|
|
||||||
|
$extent += \strlen($matches[0]);
|
||||||
|
} else {
|
||||||
|
$definition = \strtolower($label);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $State->getOrDefault(DefinitionBook::class)->lookup($definition);
|
||||||
|
|
||||||
|
if (! isset($data)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$attributes = ['href' => $data['url']];
|
||||||
|
|
||||||
|
if (isset($data['title'])) {
|
||||||
|
$attributes['title'] = $data['title'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new self($label, $attributes, $extent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return string */
|
||||||
|
public function label()
|
||||||
|
{
|
||||||
|
return $this->label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return _Metadata */
|
||||||
|
public function attributes()
|
||||||
|
{
|
||||||
|
return $this->attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Handler<Element|Text>
|
||||||
|
*/
|
||||||
|
public function stateRenderable(Parsedown $Parsedown)
|
||||||
|
{
|
||||||
|
return new Handler(
|
||||||
|
/** @return Element|Text */
|
||||||
|
function (State $State) use ($Parsedown) {
|
||||||
|
$attributes = $this->attributes;
|
||||||
|
|
||||||
|
if ($State->getOrDefault(SafeMode::class)->enabled()) {
|
||||||
|
$attributes['href'] = Element::filterUnsafeUrl($attributes['href']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Element(
|
||||||
|
'a',
|
||||||
|
$attributes,
|
||||||
|
$State->applyTo($Parsedown->lineElements($this->label))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -444,70 +444,6 @@ class Parsedown
|
|||||||
return $Inline;
|
return $Inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function inlineLink($Excerpt)
|
|
||||||
{
|
|
||||||
$Element = [
|
|
||||||
'name' => 'a',
|
|
||||||
'handler' => [
|
|
||||||
'function' => 'lineElements',
|
|
||||||
'argument' => null,
|
|
||||||
'destination' => 'elements',
|
|
||||||
],
|
|
||||||
'nonNestables' => ['Url', 'Link'],
|
|
||||||
'attributes' => [
|
|
||||||
'href' => null,
|
|
||||||
'title' => null,
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
$extent = 0;
|
|
||||||
|
|
||||||
$remainder = $Excerpt['text'];
|
|
||||||
|
|
||||||
if (\preg_match('/\[((?:[^][]++|(?R))*+)\]/', $remainder, $matches)) {
|
|
||||||
$Element['handler']['argument'] = $matches[1];
|
|
||||||
|
|
||||||
$extent += \strlen($matches[0]);
|
|
||||||
|
|
||||||
$remainder = \substr($remainder, $extent);
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (\preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*+"|\'[^\']*+\'))?\s*+[)]/', $remainder, $matches)) {
|
|
||||||
$Element['attributes']['href'] = $matches[1];
|
|
||||||
|
|
||||||
if (isset($matches[2])) {
|
|
||||||
$Element['attributes']['title'] = \substr($matches[2], 1, - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
$extent += \strlen($matches[0]);
|
|
||||||
} else {
|
|
||||||
if (\preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) {
|
|
||||||
$definition = \strlen($matches[1]) ? $matches[1] : $Element['handler']['argument'];
|
|
||||||
$definition = \strtolower($definition);
|
|
||||||
|
|
||||||
$extent += \strlen($matches[0]);
|
|
||||||
} else {
|
|
||||||
$definition = \strtolower($Element['handler']['argument']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! isset($this->DefinitionData['Reference'][$definition])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$Definition = $this->DefinitionData['Reference'][$definition];
|
|
||||||
|
|
||||||
$Element['attributes']['href'] = $Definition['url'];
|
|
||||||
$Element['attributes']['title'] = $Definition['title'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
'extent' => $extent,
|
|
||||||
'element' => $Element,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function inlineMarkup($Excerpt)
|
protected function inlineMarkup($Excerpt)
|
||||||
{
|
{
|
||||||
if ($this->markupEscaped or $this->safeMode or \strpos($Excerpt['text'], '>') === false) {
|
if ($this->markupEscaped or $this->safeMode or \strpos($Excerpt['text'], '>') === false) {
|
||||||
|
Loading…
Reference in New Issue
Block a user