Add custom image renderer to fix relative links to images #78

This commit is contained in:
Stéphane Goetz 2019-11-30 20:40:42 +01:00
parent 7acf4e5b55
commit 727c5c015e
7 changed files with 147 additions and 58 deletions

View File

@ -29,8 +29,7 @@ class CommonMarkConverter extends \League\CommonMark\CommonMarkConverter
$config['daux']['processor_instance']->extendCommonMarkEnvironment($environment); $config['daux']['processor_instance']->extendCommonMarkEnvironment($environment);
} }
$this->docParser = new DocParser($environment); parent::__construct($config, $environment);
$this->htmlRenderer = new HtmlRenderer($environment);
} }
protected function getLinkRenderer(Environment $environment) protected function getLinkRenderer(Environment $environment)

View File

@ -30,53 +30,6 @@ class LinkRenderer implements InlineRendererInterface, ConfigurationAwareInterfa
$this->parent = new \League\CommonMark\Inline\Renderer\LinkRenderer(); $this->parent = new \League\CommonMark\Inline\Renderer\LinkRenderer();
} }
/**
* @param string $url
* @return Entry
* @throws LinkNotFoundException
*/
protected function resolveInternalFile($url)
{
$triedAbsolute = false;
// Legacy absolute paths could start with
// "!" In this case we will try to find
// the file starting at the root
if ($url[0] == '!' || $url[0] == '/') {
$url = ltrim($url, '!/');
if ($file = DauxHelper::getFile($this->daux['tree'], $url)) {
return $file;
}
$triedAbsolute = true;
}
// Seems it's not an absolute path or not found,
// so we'll continue with the current folder
if ($file = DauxHelper::getFile($this->daux->getCurrentPage()->getParent(), $url)) {
return $file;
}
// If we didn't already try it, we'll
// do a pass starting at the root
if (!$triedAbsolute && $file = DauxHelper::getFile($this->daux['tree'], $url)) {
return $file;
}
throw new LinkNotFoundException("Could not locate file '$url'");
}
protected function isValidUrl($url)
{
return !empty($url) && $url[0] != '#';
}
protected function isExternalUrl($url)
{
return preg_match('#^(?:[a-z]+:)?//|^mailto:#', $url);
}
/** /**
* @param AbstractInline|Link $inline * @param AbstractInline|Link $inline
* @param ElementRendererInterface $htmlRenderer * @param ElementRendererInterface $htmlRenderer
@ -102,12 +55,12 @@ class LinkRenderer implements InlineRendererInterface, ConfigurationAwareInterfa
// empty urls and anchors should // empty urls and anchors should
// not go through the url resolver // not go through the url resolver
if (!$this->isValidUrl($url)) { if (!DauxHelper::isValidUrl($url)) {
return $element; return $element;
} }
// Absolute urls, shouldn't either // Absolute urls, shouldn't either
if ($this->isExternalUrl($url)) { if (DauxHelper::isExternalUrl($url)) {
$element->setAttribute('class', 'Link--external'); $element->setAttribute('class', 'Link--external');
return $element; return $element;
@ -121,16 +74,13 @@ class LinkRenderer implements InlineRendererInterface, ConfigurationAwareInterfa
$foundWithHash = false; $foundWithHash = false;
try { try {
$file = $this->resolveInternalFile($url); $file = DauxHelper::resolveInternalFile($this->daux, $url);
$url = DauxHelper::getRelativePath($this->daux->getCurrentPage()->getUrl(), $file->getUrl()); $url = DauxHelper::getRelativePath($this->daux->getCurrentPage()->getUrl(), $file->getUrl());
} catch (LinkNotFoundException $e) { } catch (LinkNotFoundException $e) {
// For some reason, the filename could contain a # and thus the link needs to resolve to that. // For some reason, the filename could contain a # and thus the link needs to resolve to that.
try { try {
if (strlen($urlAndHash[1] ?? "") > 0) { if (strlen($urlAndHash[1] ?? "") > 0) {
$file = $this->resolveInternalFile($url . '#' . $urlAndHash[1]); $file = DauxHelper::resolveInternalFile($this->daux, $url . '#' . $urlAndHash[1]);
$url = DauxHelper::getRelativePath($this->daux->getCurrentPage()->getUrl(), $file->getUrl()); $url = DauxHelper::getRelativePath($this->daux->getCurrentPage()->getUrl(), $file->getUrl());
$foundWithHash = true; $foundWithHash = true;
} }

View File

@ -1,5 +1,6 @@
<?php namespace Todaymade\Daux; <?php namespace Todaymade\Daux;
use Todaymade\Daux\Exception\LinkNotFoundException;
use Todaymade\Daux\Tree\Builder; use Todaymade\Daux\Tree\Builder;
use Todaymade\Daux\Tree\Directory; use Todaymade\Daux\Tree\Directory;
@ -526,4 +527,52 @@ class DauxHelper
public static function is($path, $type) { public static function is($path, $type) {
return ($type == 'dir') ? is_dir($path) : file_exists($path); return ($type == 'dir') ? is_dir($path) : file_exists($path);
} }
/**
* @param Config $config
* @param string $url
* @return Entry
* @throws LinkNotFoundException
*/
public static function resolveInternalFile($config, $url)
{
$triedAbsolute = false;
// Legacy absolute paths could start with
// "!" In this case we will try to find
// the file starting at the root
if ($url[0] == '!' || $url[0] == '/') {
$url = ltrim($url, '!/');
if ($file = DauxHelper::getFile($config['tree'], $url)) {
return $file;
}
$triedAbsolute = true;
}
// Seems it's not an absolute path or not found,
// so we'll continue with the current folder
if ($file = DauxHelper::getFile($config->getCurrentPage()->getParent(), $url)) {
return $file;
}
// If we didn't already try it, we'll
// do a pass starting at the root
if (!$triedAbsolute && $file = DauxHelper::getFile($config['tree'], $url)) {
return $file;
}
throw new LinkNotFoundException("Could not locate file '$url'");
}
public static function isValidUrl($url)
{
return !empty($url) && $url[0] != '#';
}
public static function isExternalUrl($url)
{
return preg_match('#^(?:[a-z]+:)?//|^mailto:#', $url);
}
} }

View File

@ -4,6 +4,7 @@ use League\CommonMark\ElementRendererInterface;
use League\CommonMark\HtmlElement; use League\CommonMark\HtmlElement;
use League\CommonMark\Inline\Element\AbstractInline; use League\CommonMark\Inline\Element\AbstractInline;
use League\CommonMark\Inline\Element\Link; use League\CommonMark\Inline\Element\Link;
use Todaymade\Daux\DauxHelper;
class LinkRenderer extends \Todaymade\Daux\ContentTypes\Markdown\LinkRenderer class LinkRenderer extends \Todaymade\Daux\ContentTypes\Markdown\LinkRenderer
{ {
@ -38,7 +39,7 @@ class LinkRenderer extends \Todaymade\Daux\ContentTypes\Markdown\LinkRenderer
} }
//Internal links //Internal links
$file = $this->resolveInternalFile($url); $file = DauxHelper::resolveInternalFile($this->daux, $url);
$link_props = [ $link_props = [
'ri:content-title' => trim(trim($this->daux['confluence']['prefix']) . ' ' . $file->getTitle()), 'ri:content-title' => trim(trim($this->daux['confluence']['prefix']) . ' ' . $file->getTitle()),

View File

@ -2,6 +2,7 @@
use League\CommonMark\Environment; use League\CommonMark\Environment;
use League\CommonMark\Block\Element as BlockElement; use League\CommonMark\Block\Element as BlockElement;
use League\CommonMark\Inline\Element as InlineElement;
use League\CommonMark\Event\DocumentParsedEvent; use League\CommonMark\Event\DocumentParsedEvent;
use Todaymade\Daux\Config; use Todaymade\Daux\Config;
use Todaymade\Daux\ContentTypes\Markdown\TableOfContents; use Todaymade\Daux\ContentTypes\Markdown\TableOfContents;
@ -17,5 +18,7 @@ class CommonMarkConverter extends \Todaymade\Daux\ContentTypes\Markdown\CommonMa
$processor = new TOC\Processor($config); $processor = new TOC\Processor($config);
$environment->addEventListener(DocumentParsedEvent::class, [$processor, 'onDocumentParsed']); $environment->addEventListener(DocumentParsedEvent::class, [$processor, 'onDocumentParsed']);
$environment->addBlockRenderer(TableOfContents::class, new TOC\Renderer($config)); $environment->addBlockRenderer(TableOfContents::class, new TOC\Renderer($config));
$environment->addInlineRenderer(InlineElement\Image::class, new ImageRenderer($config));
} }
} }

View File

@ -0,0 +1,87 @@
<?php namespace Todaymade\Daux\Format\HTML\ContentTypes\Markdown;
use League\CommonMark\ElementRendererInterface;
use League\CommonMark\HtmlElement;
use League\CommonMark\Inline\Element\AbstractInline;
use League\CommonMark\Inline\Element\Image;
use League\CommonMark\Inline\Renderer\InlineRendererInterface;
use League\CommonMark\Util\ConfigurationAwareInterface;
use League\CommonMark\Util\ConfigurationInterface;
use Todaymade\Daux\Config;
use Todaymade\Daux\DauxHelper;
class ImageRenderer implements InlineRendererInterface, ConfigurationAwareInterface
{
/**
* @var Config
*/
protected $daux;
/**
* @var ConfigurationInterface
*/
protected $config;
public function __construct($daux)
{
$this->daux = $daux;
$this->parent = new \League\CommonMark\Inline\Renderer\ImageRenderer();
}
/**
* Relative URLs can be done using either the folder with
* number prefix or the final name (with prefix stripped).
* This ensures that we always use the final name when generating.
*/
protected function getCleanUrl(Image $element)
{
$url = $element->getUrl();
// empty urls and anchors should
// not go through the url resolver
if (!DauxHelper::isValidUrl($url)) {
return $url;
}
// Absolute urls, shouldn't either
if (DauxHelper::isExternalUrl($url)) {
return $url;
}
try {
$file = DauxHelper::resolveInternalFile($this->daux, $url);
return DauxHelper::getRelativePath($this->daux->getCurrentPage()->getUrl(), $file->getUrl());
} catch (LinkNotFoundException $e) {
if ($this->daux->isStatic()) {
throw $e;
}
$element->setAttribute('class', 'Link--broken');
}
return $url;
}
/**
* @param Image $inline
* @param ElementRendererInterface $htmlRenderer
*
* @return HtmlElement
*/
public function render(AbstractInline $inline, ElementRendererInterface $htmlRenderer)
{
$original = $inline->getUrl();
$inline->setUrl($this->getCleanUrl($inline));
return $this->parent->render($inline, $htmlRenderer);
}
/**
* @param ConfigurationInterface $configuration
*/
public function setConfiguration(ConfigurationInterface $configuration)
{
$this->config = $configuration;
$this->parent->setConfiguration($configuration);
}
}

View File

@ -56,7 +56,7 @@ class LinkRenderer extends \Todaymade\Daux\ContentTypes\Markdown\LinkRenderer
} }
try { try {
$file = $this->resolveInternalFile($url); $file = DauxHelper::resolveInternalFile($this->daux, $url);
$url = $file->getUrl(); $url = $file->getUrl();
} catch (LinkNotFoundException $e) { } catch (LinkNotFoundException $e) {
if ($this->daux->isStatic()) { if ($this->daux->isStatic()) {