diff --git a/system/src/Grav/Common/Helpers/Excerpts.php b/system/src/Grav/Common/Helpers/Excerpts.php
new file mode 100644
index 000000000..6c95e069a
--- /dev/null
+++ b/system/src/Grav/Common/Helpers/Excerpts.php
@@ -0,0 +1,234 @@
+`
+ * @param $page The current page object
+ * @return string Returns final HTML string
+ */
+ public static function processImageHtml($html, $page)
+ {
+ $excerpt = static::getExcerptFromHtml($html, 'img');
+ $excerpt = static::processImageExcerpt($excerpt, $page);
+ $html = static::getHtmlFromExcerpt($excerpt);
+
+ return $html;
+ }
+
+ /**
+ * Get an Excerpt array from a chunk of HTML
+ *
+ * @param $html Chunk of HTML
+ * @param $tag a tag, for example `img`
+ * @return array|null returns nested array excerpt
+ */
+ public static function getExcerptFromHtml($html, $tag)
+ {
+ $doc = new \DOMDocument();
+ $doc->loadHtml($html);
+ $images = $doc->getElementsByTagName($tag);
+ $excerpt = null;
+
+ foreach ($images as $image) {
+ $attributes = [];
+ foreach ($image->attributes as $name => $value) {
+ $attributes[$name] = $value->value;
+ }
+ $excerpt = [
+ 'element' => [
+ 'name' => $image->tagName,
+ 'attributes' => $attributes
+ ]
+ ];
+ }
+
+ return $excerpt;
+ }
+
+ public static function getHtmlFromExcerpt($excerpt)
+ {
+ $element = $excerpt['element'];
+ $html = '<'.$element['name'];
+
+ if (isset($element['attributes'])) {
+ foreach ($element['attributes'] as $name => $value) {
+ if ($value === null) {
+ continue;
+ }
+ $html .= ' '.$name.'="'.$value.'"';
+ }
+ }
+
+ if (isset($element['text'])) {
+ $html .= '>';
+ $html .= $element['text'];
+ $html .= ''.$element['name'].'>';
+ } else {
+ $html .= ' />';
+ }
+
+ return $html;
+ }
+
+ public static function processLinkExcerpt($excerpt, $page)
+ {
+ $url = $excerpt['element']['attributes']['href'];
+
+ $url_parts = parse_url(htmlspecialchars_decode(urldecode($url)));
+
+ // if there is a query, then parse it and build action calls
+ if (isset($url_parts['query'])) {
+ $actions = array_reduce(explode('&', $url_parts['query']), function ($carry, $item) {
+ $parts = explode('=', $item, 2);
+ $value = isset($parts[1]) ? rawurldecode($parts[1]) : true;
+ $carry[$parts[0]] = $value;
+
+ return $carry;
+ }, []);
+
+ // valid attributes supported
+ $valid_attributes = ['rel', 'target', 'id', 'class', 'classes'];
+
+ // Unless told to not process, go through actions
+ if (array_key_exists('noprocess', $actions)) {
+ unset($actions['noprocess']);
+ } else {
+ // loop through actions for the image and call them
+ foreach ($actions as $attrib => $value) {
+ $key = $attrib;
+
+ if (in_array($attrib, $valid_attributes)) {
+ // support both class and classes
+ if ($attrib == 'classes') {
+ $attrib = 'class';
+ }
+ $excerpt['element']['attributes'][$attrib] = str_replace(',', ' ', $value);
+ unset($actions[$key]);
+ }
+ }
+ }
+
+ $url_parts['query'] = http_build_query($actions, null, '&', PHP_QUERY_RFC3986);
+ }
+
+ // if no query elements left, unset query
+ if (empty($url_parts['query'])) {
+ unset ($url_parts['query']);
+ }
+
+ // set path to / if not set
+ if (empty($url_parts['path'])) {
+ $url_parts['path'] = '';
+ }
+
+ // if special scheme, just return
+ if(isset($url_parts['scheme']) && !Utils::startsWith($url_parts['scheme'], 'http')) {
+ return $excerpt;
+ }
+
+ // Get Type
+ if (isset($excerpt['type'])) {
+ $type = $excerpt['type'];
+ } else {
+ $type = 'link';
+ }
+
+ // handle paths and such
+ $url_parts = Uri::convertUrl($page, $url_parts, $type);
+
+ // build the URL from the component parts and set it on the element
+ $excerpt['element']['attributes']['href'] = Uri::buildUrl($url_parts);
+
+ return $excerpt;
+ }
+
+ public static function processImageExcerpt($excerpt, $page)
+ {
+ $url = $excerpt['element']['attributes']['src'];
+
+ $url_parts = parse_url(htmlspecialchars_decode(urldecode($url)));
+
+ $this_host = isset($url_parts['host']) && $url_parts['host'] == Grav::instance()['uri']->host();
+
+ // if there is no host set but there is a path, the file is local
+ if ((!isset($url_parts['host']) || $this_host) && isset($url_parts['path'])) {
+
+ $path_parts = pathinfo($url_parts['path']);
+ $actions = [];
+ $media = null;
+
+ // get the local path to page media if possible
+ if ($path_parts['dirname'] == $page->url(false, false, false)) {
+ // get the media objects for this page
+ $media = $page->media();
+ } else {
+ // see if this is an external page to this one
+ $base_url = rtrim(Grav::instance()['base_url_relative'] . Grav::instance()['pages']->base(), '/');
+ $page_route = '/' . ltrim(str_replace($base_url, '', $path_parts['dirname']), '/');
+
+ $ext_page = Grav::instance()['pages']->dispatch($page_route, true);
+ if ($ext_page) {
+ $media = $ext_page->media();
+ }
+ }
+
+ // if there is a media file that matches the path referenced..
+ if ($media && isset($media->all()[$path_parts['basename']])) {
+ // get the medium object
+ /** @var Medium $medium */
+ $medium = $media->all()[$path_parts['basename']];
+
+ // if there is a query, then parse it and build action calls
+ if (isset($url_parts['query'])) {
+ $actions = array_reduce(explode('&', $url_parts['query']), function ($carry, $item) {
+ $parts = explode('=', $item, 2);
+ $value = isset($parts[1]) ? $parts[1] : null;
+ $carry[] = ['method' => $parts[0], 'params' => $value];
+
+ return $carry;
+ }, []);
+ }
+
+ // loop through actions for the image and call them
+ foreach ($actions as $action) {
+ $medium = call_user_func_array([$medium, $action['method']],
+ explode(',', $action['params']));
+ }
+
+ if (isset($url_parts['fragment'])) {
+ $medium->urlHash($url_parts['fragment']);
+ }
+
+ $alt = $excerpt['element']['attributes']['alt'] ?: '';
+ $title = $excerpt['element']['attributes']['title'] ?: '';
+ $class = isset($excerpt['element']['attributes']['class']) ? $excerpt['element']['attributes']['class'] : '';
+ $id = isset($excerpt['element']['attributes']['id']) ? $excerpt['element']['attributes']['id'] : '';
+
+ $excerpt['element'] = $medium->parseDownElement($title, $alt, $class, $id, true);
+
+ } else {
+ // not a current page media file, see if it needs converting to relative
+ $excerpt['element']['attributes']['src'] = Uri::buildUrl($url_parts);
+ }
+ }
+
+ return $excerpt;
+ }
+
+}
diff --git a/system/src/Grav/Common/Markdown/ParsedownGravTrait.php b/system/src/Grav/Common/Markdown/ParsedownGravTrait.php
index 895754e32..a02ca8316 100644
--- a/system/src/Grav/Common/Markdown/ParsedownGravTrait.php
+++ b/system/src/Grav/Common/Markdown/ParsedownGravTrait.php
@@ -9,7 +9,7 @@
namespace Grav\Common\Markdown;
use Grav\Common\Grav;
-use Grav\Common\Page\Medium\Medium;
+use Grav\Common\Helpers\Excerpts;
use Grav\Common\Uri;
use Grav\Common\Utils;
use RocketTheme\Toolbox\Event\Event;
@@ -19,13 +19,6 @@ trait ParsedownGravTrait
/** @var Page $page */
protected $page;
- /** @var Pages $pages */
-// protected $pages;
-
- /** @var Uri $uri */
-// protected $uri;
-
-// protected $pages_dir;
protected $special_chars;
protected $twig_link_regex = '/\!*\[(?:.*)\]\((\{([\{%#])\s*(.*?)\s*(?:\2|\})\})\)/';
@@ -43,10 +36,7 @@ trait ParsedownGravTrait
$grav = Grav::instance();
$this->page = $page;
-// $this->pages = $grav['pages'];
-// $this->uri = $grav['uri'];
$this->BlockTypes['{'] [] = "TwigTag";
-// $this->pages_dir = Grav::instance()['locator']->findResource('page://');
$this->special_chars = ['>' => 'gt', '<' => 'lt', '"' => 'quot'];
if ($defaults === null) {
@@ -206,7 +196,7 @@ trait ParsedownGravTrait
// if this is an image process it
if (isset($excerpt['element']['attributes']['src'])) {
- $excerpt = Utils::processImageExcerpt($excerpt, $this->page);
+ $excerpt = Excerpts::processImageExcerpt($excerpt, $this->page);
}
return $excerpt;
@@ -214,12 +204,6 @@ trait ParsedownGravTrait
protected function inlineLink($excerpt)
{
- if (isset($excerpt['type'])) {
- $type = $excerpt['type'];
- } else {
- $type = 'link';
- }
-
// do some trickery to get around Parsedown requirement for valid URL if its Twig in there
if (preg_match($this->twig_link_regex, $excerpt['text'], $matches)) {
$excerpt['text'] = str_replace($matches[1], '/', $excerpt['text']);
@@ -234,63 +218,7 @@ trait ParsedownGravTrait
// if this is a link
if (isset($excerpt['element']['attributes']['href'])) {
- $url = parse_url(htmlspecialchars_decode($excerpt['element']['attributes']['href']));
-
- // if there is a query, then parse it and build action calls
- if (isset($url['query'])) {
- $actions = array_reduce(explode('&', $url['query']), function ($carry, $item) {
- $parts = explode('=', $item, 2);
- $value = isset($parts[1]) ? rawurldecode($parts[1]) : true;
- $carry[$parts[0]] = $value;
-
- return $carry;
- }, []);
-
- // valid attributes supported
- $valid_attributes = ['rel', 'target', 'id', 'class', 'classes'];
-
- // Unless told to not process, go through actions
- if (array_key_exists('noprocess', $actions)) {
- unset($actions['noprocess']);
- } else {
- // loop through actions for the image and call them
- foreach ($actions as $attrib => $value) {
- $key = $attrib;
-
- if (in_array($attrib, $valid_attributes)) {
- // support both class and classes
- if ($attrib == 'classes') {
- $attrib = 'class';
- }
- $excerpt['element']['attributes'][$attrib] = str_replace(',', ' ', $value);
- unset($actions[$key]);
- }
- }
- }
-
- $url['query'] = http_build_query($actions, null, '&', PHP_QUERY_RFC3986);
- }
-
- // if no query elements left, unset query
- if (empty($url['query'])) {
- unset ($url['query']);
- }
-
- // set path to / if not set
- if (empty($url['path'])) {
- $url['path'] = '';
- }
-
- // if special scheme, just return
- if(isset($url['scheme']) && !Utils::startsWith($url['scheme'], 'http')) {
- return $excerpt;
- }
-
- // handle paths and such
- $url = Uri::convertUrl($this->page, $url, $type);
-
- // build the URL from the component parts and set it on the element
- $excerpt['element']['attributes']['href'] = Uri::buildUrl($url);
+ $excerpt = Excerpts::processLinkExcerpt($excerpt, $this->page);
}
return $excerpt;
diff --git a/system/src/Grav/Common/Utils.php b/system/src/Grav/Common/Utils.php
index 3c8a9f607..c63aa8ffe 100644
--- a/system/src/Grav/Common/Utils.php
+++ b/system/src/Grav/Common/Utils.php
@@ -9,10 +9,7 @@
namespace Grav\Common;
use DateTime;
-use DateTimeZone;
-use Grav\Common\Grav;
use Grav\Common\Helpers\Truncator;
-use Grav\Common\Page\Medium\Medium;
use RocketTheme\Toolbox\Event\Event;
abstract class Utils
@@ -429,150 +426,6 @@ abstract class Utils
return $root . implode('/', $ret);
}
- /**
- * Process Grav image media URL from HTML tag
- *
- * @param $html HTML tag e.g. `
`
- * @param $page The current page object
- * @return string Returns final HTML string
- */
- public static function processImageHtml($html, $page)
- {
- $excerpt = static::getExcerptFromHtml($html, 'img');
- $excerpt = static::processImageExcerpt($excerpt, $page);
- $html = static::getHtmlFromExcerpt($excerpt);
-
- return $html;
- }
-
- /**
- * Get an Excerpt array from a chunk of HTML
- *
- * @param $html Chunk of HTML
- * @param $tag a tag, for example `img`
- * @return array|null returns nested array excerpt
- */
- public static function getExcerptFromHtml($html, $tag)
- {
- $doc = new \DOMDocument();
- $doc->loadHtml($html);
- $images = $doc->getElementsByTagName($tag);
- $excerpt = null;
-
- foreach ($images as $image) {
- $attributes = [];
- foreach ($image->attributes as $name => $value) {
- $attributes[$name] = $value->value;
- }
- $excerpt = [
- 'element' => [
- 'name' => $image->tagName,
- 'attributes' => $attributes
- ]
- ];
- }
-
- return $excerpt;
- }
-
- public static function getHtmlFromExcerpt($excerpt)
- {
- $element = $excerpt['element'];
- $html = '<'.$element['name'];
-
- if (isset($element['attributes'])) {
- foreach ($element['attributes'] as $name => $value) {
- if ($value === null) {
- continue;
- }
- $html .= ' '.$name.'="'.$value.'"';
- }
- }
-
- if (isset($element['text'])) {
- $html .= '>';
- $html .= $element['text'];
- $html .= ''.$element['name'].'>';
- } else {
- $html .= ' />';
- }
-
- return $html;
- }
-
- public static function processImageExcerpt($excerpt, $page)
- {
- $url = $excerpt['element']['attributes']['src'];
-
- $url_parts = parse_url(htmlspecialchars_decode(urldecode($url)));
-
- $this_host = isset($url_parts['host']) && $url_parts['host'] == Grav::instance()['uri']->host();
-
- // if there is no host set but there is a path, the file is local
- if ((!isset($url_parts['host']) || $this_host) && isset($url_parts['path'])) {
-
- $path_parts = pathinfo($url_parts['path']);
- $actions = [];
- $media = null;
-
- // get the local path to page media if possible
- if ($path_parts['dirname'] == $page->url(false, false, false)) {
- // get the media objects for this page
- $media = $page->media();
- } else {
- // see if this is an external page to this one
- $base_url = rtrim(Grav::instance()['base_url_relative'] . Grav::instance()['pages']->base(), '/');
- $page_route = '/' . ltrim(str_replace($base_url, '', $path_parts['dirname']), '/');
-
- $ext_page = Grav::instance()['pages']->dispatch($page_route, true);
- if ($ext_page) {
- $media = $ext_page->media();
- }
- }
-
- // if there is a media file that matches the path referenced..
- if ($media && isset($media->all()[$path_parts['basename']])) {
- // get the medium object
- /** @var Medium $medium */
- $medium = $media->all()[$path_parts['basename']];
-
- // if there is a query, then parse it and build action calls
- if (isset($url_parts['query'])) {
- $actions = array_reduce(explode('&', $url_parts['query']), function ($carry, $item) {
- $parts = explode('=', $item, 2);
- $value = isset($parts[1]) ? $parts[1] : null;
- $carry[] = ['method' => $parts[0], 'params' => $value];
-
- return $carry;
- }, []);
- }
-
- // loop through actions for the image and call them
- foreach ($actions as $action) {
- $medium = call_user_func_array([$medium, $action['method']],
- explode(',', $action['params']));
- }
-
- if (isset($url_parts['fragment'])) {
- $medium->urlHash($url_parts['fragment']);
- }
-
- $alt = $excerpt['element']['attributes']['alt'] ?: '';
- $title = $excerpt['element']['attributes']['title'] ?: '';
- $class = isset($excerpt['element']['attributes']['class']) ? $excerpt['element']['attributes']['class'] : '';
- $id = isset($excerpt['element']['attributes']['id']) ? $excerpt['element']['attributes']['id'] : '';
-
- $excerpt['element'] = $medium->parseDownElement($title, $alt, $class, $id, true);
-
- } else {
- // not a current page media file, see if it needs converting to relative
- $excerpt['element']['attributes']['src'] = Uri::buildUrl($url);
- }
- }
-
- return $excerpt;
- }
-
/**
* Check whether a function is disabled in the PHP settings
*
diff --git a/tests/unit/Grav/Common/Helpers/ExcerptsTest.php b/tests/unit/Grav/Common/Helpers/ExcerptsTest.php
new file mode 100644
index 000000000..da3b6921b
--- /dev/null
+++ b/tests/unit/Grav/Common/Helpers/ExcerptsTest.php
@@ -0,0 +1,86 @@
+grav = $grav();
+ $this->pages = $this->grav['pages'];
+ $this->config = $this->grav['config'];
+ $this->uri = $this->grav['uri'];
+ $this->language = $this->grav['language'];
+ $this->old_home = $this->config->get('system.home.alias');
+ $this->config->set('system.home.alias', '/item1');
+ $this->config->set('system.absolute_urls', false);
+ $this->config->set('system.languages.supported', []);
+
+ unset($this->grav['language']);
+ $this->grav['language'] = new Language($this->grav);
+
+ /** @var UniformResourceLocator $locator */
+ $locator = $this->grav['locator'];
+ $locator->addPath('page', '', 'tests/fake/nested-site/user/pages', false);
+ $this->pages->init();
+
+ $defaults = [
+ 'extra' => false,
+ 'auto_line_breaks' => false,
+ 'auto_url_links' => false,
+ 'escape_markup' => false,
+ 'special_chars' => ['>' => 'gt', '<' => 'lt'],
+ ];
+ $this->page = $this->pages->dispatch('/item2/item2-2');
+ $this->uri->initializeWithURL('http://testing.dev/item2/item2-2')->init();
+ }
+
+ protected function _after()
+ {
+ $this->config->set('system.home.alias', $this->old_home);
+ }
+
+
+ public function testProcessImageHtml()
+ {
+
+
+ $this->assertSame('',
+ Excerpts::processImageHtml('
', $this->page));
+
+ }
+
+}
diff --git a/tests/unit/Grav/Common/Markdown/ParsedownTest.php b/tests/unit/Grav/Common/Markdown/ParsedownTest.php
index ec4521b4d..104188fb0 100644
--- a/tests/unit/Grav/Common/Markdown/ParsedownTest.php
+++ b/tests/unit/Grav/Common/Markdown/ParsedownTest.php
@@ -73,6 +73,16 @@ class ParsedownTest extends \Codeception\TestCase\Test
public function testImages()
{
+ $this->config->set('system.languages.supported', ['fr','en']);
+ unset($this->grav['language']);
+ $this->grav['language'] = new Language($this->grav);
+ $this->uri->initializeWithURL('http://testing.dev/fr/item2/item2-2')->init();
+
+ $this->assertSame('

<\/p>|',
+ $this->parsedown->text(''));
+
$this->uri->initializeWithURL('http://testing.dev/item2/item2-2')->init();
$this->assertSame('



<\/p>|',
- $this->parsedown->text(''));
}
public function testImagesSubDir()