Add Markdown Extra formatter

Library: [Parsedown Extra](https://github.com/erusev/parsedown-extra)

Also sort dependencies alphabetically.

Fixes #1169
This commit is contained in:
ArthurHoaro 2020-08-27 15:25:18 +02:00
parent 84045ffbb1
commit 8fabcd0224
7 changed files with 256 additions and 13 deletions

View file

@ -0,0 +1,24 @@
<?php
namespace Shaarli\Formatter;
use Shaarli\Config\ConfigManager;
/**
* Class BookmarkMarkdownExtraFormatter
*
* Format bookmark description into MarkdownExtra format.
*
* @see https://michelf.ca/projects/php-markdown/extra/
*
* @package Shaarli\Formatter
*/
class BookmarkMarkdownExtraFormatter extends BookmarkMarkdownFormatter
{
public function __construct(ConfigManager $conf, bool $isLoggedIn)
{
parent::__construct($conf, $isLoggedIn);
$this->parsedown = new \ParsedownExtra();
}
}

View file

@ -30,7 +30,7 @@ public function index(Request $request, Response $response): Response
'theme_available',
ThemeUtils::getThemes($this->container->conf->get('resource.raintpl_tpl'))
);
$this->assignView('formatter_available', ['default', 'markdown']);
$this->assignView('formatter_available', ['default', 'markdown', 'markdownExtra']);
list($continents, $cities) = generateTimeZoneData(
timezone_identifiers_list(),
$this->container->conf->get('general.timezone')

View file

@ -10,6 +10,7 @@
},
"keywords": ["bookmark", "link", "share", "web"],
"config": {
"sort-packages": true,
"platform": {
"php": "7.1.29"
}
@ -18,12 +19,13 @@
"php": ">=7.1",
"ext-json": "*",
"ext-zlib": "*",
"shaarli/netscape-bookmark-parser": "^2.1",
"erusev/parsedown": "^1.6",
"slim/slim": "^3.0",
"arthurhoaro/web-thumbnailer": "^2.0",
"erusev/parsedown": "^1.6",
"erusev/parsedown-extra": "^0.8.1",
"gettext/gettext": "^4.4",
"pubsubhubbub/publisher": "dev-master",
"gettext/gettext": "^4.4"
"shaarli/netscape-bookmark-parser": "^2.1",
"slim/slim": "^3.0"
},
"require-dev": {
"roave/security-advisories": "dev-master",

67
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "98520a05a7185503ee13d05ffaa535f6",
"content-hash": "f84918821b0dceb0cd569875c0418bb8",
"packages": [
{
"name": "arthurhoaro/web-thumbnailer",
@ -107,6 +107,57 @@
},
"time": "2019-12-30T22:54:17+00:00"
},
{
"name": "erusev/parsedown-extra",
"version": "0.8.1",
"source": {
"type": "git",
"url": "https://github.com/erusev/parsedown-extra.git",
"reference": "91ac3ff98f0cea243bdccc688df43810f044dcef"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/erusev/parsedown-extra/zipball/91ac3ff98f0cea243bdccc688df43810f044dcef",
"reference": "91ac3ff98f0cea243bdccc688df43810f044dcef",
"shasum": ""
},
"require": {
"erusev/parsedown": "^1.7.4"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35"
},
"type": "library",
"autoload": {
"psr-0": {
"ParsedownExtra": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Emanuil Rusev",
"email": "hello@erusev.com",
"homepage": "http://erusev.com"
}
],
"description": "An extension of Parsedown that adds support for Markdown Extra.",
"homepage": "https://github.com/erusev/parsedown-extra",
"keywords": [
"markdown",
"markdown extra",
"parsedown",
"parser"
],
"support": {
"issues": "https://github.com/erusev/parsedown-extra/issues",
"source": "https://github.com/erusev/parsedown-extra/tree/0.8.x"
},
"time": "2019-12-30T23:20:37+00:00"
},
{
"name": "gettext/gettext",
"version": "v4.8.2",
@ -1577,12 +1628,12 @@
"source": {
"type": "git",
"url": "https://github.com/Roave/SecurityAdvisories.git",
"reference": "0749ceaf15c136d085b722a5bb88141398a54142"
"reference": "ba5d234b3a1559321b816b64aafc2ce6728799ff"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/0749ceaf15c136d085b722a5bb88141398a54142",
"reference": "0749ceaf15c136d085b722a5bb88141398a54142",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/ba5d234b3a1559321b816b64aafc2ce6728799ff",
"reference": "ba5d234b3a1559321b816b64aafc2ce6728799ff",
"shasum": ""
},
"conflict": {
@ -1642,7 +1693,7 @@
"ezsystems/ezplatform-kernel": ">=1,<1.0.2.1",
"ezsystems/ezplatform-user": ">=1,<1.0.1",
"ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.14.2|>=6,<6.7.9.1|>=6.8,<6.13.6.3|>=7,<7.2.4.1|>=7.3,<7.3.2.1|>=7.5,<7.5.7.1",
"ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.14.1|>=2011,<2017.12.7.2|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3|>=2019.3,<2019.3.4.2",
"ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.14.2|>=2011,<2017.12.7.3|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3|>=2019.3,<2019.3.5.1",
"ezsystems/platform-ui-assets-bundle": ">=4.2,<4.2.3",
"ezsystems/repository-forms": ">=2.3,<2.3.2.1",
"ezyang/htmlpurifier": "<4.1.1",
@ -1685,6 +1736,8 @@
"mittwald/typo3_forum": "<1.2.1",
"monolog/monolog": ">=1.8,<1.12",
"namshi/jose": "<2.2",
"nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6",
"nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13",
"nystudio107/craft-seomatic": "<3.3",
"nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1",
"october/backend": ">=1.0.319,<1.0.467",
@ -1720,6 +1773,7 @@
"privatebin/privatebin": "<1.2.2|>=1.3,<1.3.2",
"propel/propel": ">=2-alpha.1,<=2-alpha.7",
"propel/propel1": ">=1,<=1.7.1",
"pterodactyl/panel": "<0.7.19|>=1-rc.0,<=1-rc.6",
"pusher/pusher-php-server": "<2.2.1",
"rainlab/debugbar-plugin": "<3.1",
"robrichards/xmlseclibs": "<3.0.4",
@ -1805,6 +1859,7 @@
"typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5",
"typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4",
"typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1",
"typo3fluid/fluid": ">=2,<2.0.5|>=2.1,<2.1.4|>=2.2,<2.2.1|>=2.3,<2.3.5|>=2.4,<2.4.1|>=2.5,<2.5.5|>=2.6,<2.6.1",
"ua-parser/uap-php": "<3.8",
"usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2",
"verot/class.upload.php": "<=1.0.3|>=2,<=2.0.4",
@ -1878,7 +1933,7 @@
"type": "tidelift"
}
],
"time": "2020-09-24T17:02:11+00:00"
"time": "2020-10-08T21:02:27+00:00"
},
{
"name": "sebastian/code-unit-reverse-lookup",

View file

@ -0,0 +1,162 @@
<?php
namespace Shaarli\Formatter;
use DateTime;
use PHPUnit\Framework\TestCase;
use Shaarli\Bookmark\Bookmark;
use Shaarli\Config\ConfigManager;
/**
* Class BookmarkMarkdownExtraFormatterTest
* @package Shaarli\Formatter
*/
class BookmarkMarkdownExtraFormatterTest extends TestCase
{
/** @var string Path of test config file */
protected static $testConf = 'sandbox/config';
/** @var BookmarkFormatter */
protected $formatter;
/** @var ConfigManager instance */
protected $conf;
/**
* Initialize formatter instance.
*/
public function setUp(): void
{
copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php');
$this->conf = new ConfigManager(self::$testConf);
$this->formatter = new BookmarkMarkdownExtraFormatter($this->conf, true);
}
/**
* Test formatting a bookmark with all its attribute filled.
*/
public function testFormatExtra(): void
{
$bookmark = new Bookmark();
$bookmark->setId($id = 11);
$bookmark->setShortUrl($short = 'abcdef');
$bookmark->setUrl('https://sub.domain.tld?query=here&for=real#hash');
$bookmark->setTitle($title = 'This is a <strong>bookmark</strong>');
$bookmark->setDescription('<h2>Content</h2><p>`Here is some content</p>');
$bookmark->setTags($tags = ['tag1', 'bookmark', 'other', '<script>alert("xss");</script>']);
$bookmark->setThumbnail('http://domain2.tdl2/?type=img&name=file.png');
$bookmark->setSticky(true);
$bookmark->setCreated($created = DateTime::createFromFormat('Ymd_His', '20190521_190412'));
$bookmark->setUpdated($updated = DateTime::createFromFormat('Ymd_His', '20190521_191213'));
$bookmark->setPrivate(true);
$link = $this->formatter->format($bookmark);
$this->assertEquals($id, $link['id']);
$this->assertEquals($short, $link['shorturl']);
$this->assertEquals('https://sub.domain.tld?query=here&amp;for=real#hash', $link['url']);
$this->assertEquals(
'https://sub.domain.tld?query=here&amp;for=real#hash',
$link['real_url']
);
$this->assertEquals('This is a &lt;strong&gt;bookmark&lt;/strong&gt;', $link['title']);
$this->assertEquals(
'<div class="markdown"><p>'.
'&lt;h2&gt;Content&lt;/h2&gt;&lt;p&gt;`Here is some content&lt;/p&gt;'.
'</p></div>',
$link['description']
);
$tags[3] = '&lt;script&gt;alert(&quot;xss&quot;);&lt;/script&gt;';
$this->assertEquals($tags, $link['taglist']);
$this->assertEquals(implode(' ', $tags), $link['tags']);
$this->assertEquals(
'http://domain2.tdl2/?type=img&amp;name=file.png',
$link['thumbnail']
);
$this->assertEquals($created, $link['created']);
$this->assertEquals($created->getTimestamp(), $link['timestamp']);
$this->assertEquals($updated, $link['updated']);
$this->assertEquals($updated->getTimestamp(), $link['updated_timestamp']);
$this->assertTrue($link['private']);
$this->assertTrue($link['sticky']);
$this->assertEquals('private', $link['class']);
}
/**
* Test formatting a bookmark with all its attribute filled.
*/
public function testFormatExtraMinimal(): void
{
$bookmark = new Bookmark();
$link = $this->formatter->format($bookmark);
$this->assertEmpty($link['id']);
$this->assertEmpty($link['shorturl']);
$this->assertEmpty($link['url']);
$this->assertEmpty($link['real_url']);
$this->assertEmpty($link['title']);
$this->assertEmpty($link['description']);
$this->assertEmpty($link['taglist']);
$this->assertEmpty($link['tags']);
$this->assertEmpty($link['thumbnail']);
$this->assertEmpty($link['created']);
$this->assertEmpty($link['timestamp']);
$this->assertEmpty($link['updated']);
$this->assertEmpty($link['updated_timestamp']);
$this->assertFalse($link['private']);
$this->assertFalse($link['sticky']);
$this->assertEmpty($link['class']);
}
/**
* Make sure that the description is properly formatted by the default formatter.
*/
public function testFormatExtrraDescription(): void
{
$description = 'This a <strong>description</strong>'. PHP_EOL;
$description .= 'text https://sub.domain.tld?query=here&for=real#hash more text'. PHP_EOL;
$description .= 'Also, there is an #hashtag added'. PHP_EOL;
$description .= ' A N D KEEP SPACES ! '. PHP_EOL;
$description .= '# Header {.class}'. PHP_EOL;
$bookmark = new Bookmark();
$bookmark->setDescription($description);
$link = $this->formatter->format($bookmark);
$description = '<div class="markdown"><p>';
$description .= 'This a &lt;strong&gt;description&lt;/strong&gt;<br />'. PHP_EOL;
$url = 'https://sub.domain.tld?query=here&amp;for=real#hash';
$description .= 'text <a href="'. $url .'">'. $url .'</a> more text<br />'. PHP_EOL;
$description .= 'Also, there is an <a href="./add-tag/hashtag">#hashtag</a> added<br />'. PHP_EOL;
$description .= 'A N D KEEP SPACES ! </p>' . PHP_EOL;
$description .= '<h1 class="class">Header</h1>';
$description .= '</div>';
$this->assertEquals($description, $link['description']);
}
/**
* Test formatting URL with an index_url set
* It should prepend relative links.
*/
public function testFormatExtraNoteWithIndexUrl(): void
{
$bookmark = new Bookmark();
$bookmark->setUrl($short = '?abcdef');
$description = 'Text #hashtag more text';
$bookmark->setDescription($description);
$this->formatter->addContextData('index_url', $root = 'https://domain.tld/hithere/');
$description = '<div class="markdown"><p>';
$description .= 'Text <a href="'. $root .'./add-tag/hashtag">#hashtag</a> more text';
$description .= '</p></div>';
$link = $this->formatter->format($bookmark);
$this->assertEquals($root . $short, $link['url']);
$this->assertEquals($root . $short, $link['real_url']);
$this->assertEquals(
$description,
$link['description']
);
}
}

View file

@ -51,7 +51,7 @@ public function testIndex(): void
static::assertSame('general.title', $assignedVariables['title']);
static::assertSame('resource.theme', $assignedVariables['theme']);
static::assertEmpty($assignedVariables['theme_available']);
static::assertSame(['default', 'markdown'], $assignedVariables['formatter_available']);
static::assertSame(['default', 'markdown', 'markdownExtra'], $assignedVariables['formatter_available']);
static::assertNotEmpty($assignedVariables['continents']);
static::assertNotEmpty($assignedVariables['cities']);
static::assertSame('general.retrieve_description', $assignedVariables['retrieve_description']);

View file

@ -8,7 +8,7 @@
<link href="{$asset_path}/img/favicon.png#" rel="shortcut icon" type="image/png" />
<link href="{$asset_path}/img/apple-touch-icon.png#" rel="apple-touch-icon" sizes="180x180" />
<link type="text/css" rel="stylesheet" href="{$asset_path}/css/shaarli.min.css?v={$version_hash}#" />
{if="$formatter==='markdown'"}
{if="strpos($formatter, 'markdown') !== false"}
<link type="text/css" rel="stylesheet" href="{$asset_path}/css/markdown.min.css?v={$version_hash}#" />
{/if}
{loop="$plugins_includes.css_files"}