]> git.immae.eu Git - github/shaarli/Shaarli.git/commitdiff
Add Markdown Extra formatter 1521/head
authorArthurHoaro <arthur@hoa.ro>
Thu, 27 Aug 2020 13:25:18 +0000 (15:25 +0200)
committerArthurHoaro <arthur@hoa.ro>
Tue, 13 Oct 2020 10:20:34 +0000 (12:20 +0200)
Library: [Parsedown Extra](https://github.com/erusev/parsedown-extra)

Also sort dependencies alphabetically.

Fixes #1169

application/formatter/BookmarkMarkdownExtraFormatter.php [new file with mode: 0644]
application/front/controller/admin/ConfigureController.php
composer.json
composer.lock
tests/formatter/BookmarkMarkdownExtraFormatterTest.php [new file with mode: 0644]
tests/front/controller/admin/ConfigureControllerTest.php
tpl/default/includes.html

diff --git a/application/formatter/BookmarkMarkdownExtraFormatter.php b/application/formatter/BookmarkMarkdownExtraFormatter.php
new file mode 100644 (file)
index 0000000..0694b23
--- /dev/null
@@ -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();
+    }
+}
index e675fccabad0eacf408acc0901c113d0e777a5c9..0ed7ad81086d93b6a0c0d39e3a539dd398a8fb62 100644 (file)
@@ -30,7 +30,7 @@ class ConfigureController extends ShaarliAdminController
             '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')
index cd9fcf5b22e6b1df223858e93434e7877472764d..7e675623c051abf9e917becbbf57e9107cb580f9 100644 (file)
@@ -10,6 +10,7 @@
     },
     "keywords": ["bookmark", "link", "share", "web"],
     "config": {
+        "sort-packages": true,
         "platform": {
             "php": "7.1.29"
         }
         "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",
index 2c8b0ea7bc675e9797c6957178733aa03cd3b272..e02491ff3f7c70db800e7433d16461faac5866e4 100644 (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",
             },
             "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",
             "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": {
                 "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",
                 "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",
                 "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",
                 "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",
                     "type": "tidelift"
                 }
             ],
-            "time": "2020-09-24T17:02:11+00:00"
+            "time": "2020-10-08T21:02:27+00:00"
         },
         {
             "name": "sebastian/code-unit-reverse-lookup",
diff --git a/tests/formatter/BookmarkMarkdownExtraFormatterTest.php b/tests/formatter/BookmarkMarkdownExtraFormatterTest.php
new file mode 100644 (file)
index 0000000..d4941ef
--- /dev/null
@@ -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']
+        );
+    }
+}
index aca6cff310394979c1677f22b41789d1f2571c9d..d82db0a7c3e4692b4fb9bd9be81bdde4def86a11 100644 (file)
@@ -51,7 +51,7 @@ class ConfigureControllerTest extends TestCase
         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']);
index 227f9b52ae805080ec089ff59b1d2e16d0ee0dfd..09768ac47905908bc5cbc274e230a407541bd946 100644 (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"}