diff --git a/src/Components/Inlines/Link.php b/src/Components/Inlines/Link.php new file mode 100644 index 0000000..b0f9bd4 --- /dev/null +++ b/src/Components/Inlines/Link.php @@ -0,0 +1,128 @@ +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 + */ + 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)) + ); + } + ); + } +} diff --git a/src/Parsedown.php b/src/Parsedown.php index a2e666f..fc69bad 100644 --- a/src/Parsedown.php +++ b/src/Parsedown.php @@ -444,70 +444,6 @@ class Parsedown 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) { if ($this->markupEscaped or $this->safeMode or \strpos($Excerpt['text'], '>') === false) {