fix(markdown-editor): remove unnecessary buttons for podcast and episode editors + add extensions

update CommonMark to v2 + add Autolink, SmartPunct and DisallowedRawHtml extensions
This commit is contained in:
Yassine Doghri 2022-02-02 17:01:19 +00:00
parent f304d97b14
commit 9c4f60e00b
11 changed files with 625 additions and 274 deletions

View File

@ -26,7 +26,12 @@ use CodeIgniter\Entity\Entity;
use CodeIgniter\Files\File;
use CodeIgniter\HTTP\Files\UploadedFile;
use CodeIgniter\I18n\Time;
use League\CommonMark\CommonMarkConverter;
use League\CommonMark\Environment\Environment;
use League\CommonMark\Extension\Autolink\AutolinkExtension;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
use League\CommonMark\MarkdownConverter;
use RuntimeException;
/**
@ -473,13 +478,21 @@ class Episode extends Entity
public function setDescriptionMarkdown(string $descriptionMarkdown): static
{
$converter = new CommonMarkConverter([
'html_input' => 'strip',
$config = [
'html_input' => 'escape',
'allow_unsafe_links' => false,
]);
];
$environment = new Environment($config);
$environment->addExtension(new CommonMarkCoreExtension());
$environment->addExtension(new AutolinkExtension());
$environment->addExtension(new SmartPunctExtension());
$environment->addExtension(new DisallowedRawHtmlExtension());
$converter = new MarkdownConverter($environment);
$this->attributes['description_markdown'] = $descriptionMarkdown;
$this->attributes['description_html'] = $converter->convertToHtml($descriptionMarkdown);
$this->attributes['description_html'] = $converter->convert($descriptionMarkdown);
return $this;
}

View File

@ -12,7 +12,12 @@ namespace App\Entities;
use CodeIgniter\Entity\Entity;
use CodeIgniter\I18n\Time;
use League\CommonMark\CommonMarkConverter;
use League\CommonMark\Environment\Environment;
use League\CommonMark\Extension\Autolink\AutolinkExtension;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
use League\CommonMark\MarkdownConverter;
/**
* @property int $id
@ -49,13 +54,20 @@ class Page extends Entity
public function setContentMarkdown(string $contentMarkdown): static
{
$converter = new CommonMarkConverter([
'html_input' => 'strip',
$config = [
'allow_unsafe_links' => false,
]);
];
$environment = new Environment($config);
$environment->addExtension(new CommonMarkCoreExtension());
$environment->addExtension(new AutolinkExtension());
$environment->addExtension(new SmartPunctExtension());
$environment->addExtension(new DisallowedRawHtmlExtension());
$converter = new MarkdownConverter($environment);
$this->attributes['content_markdown'] = $contentMarkdown;
$this->attributes['content_html'] = $converter->convertToHtml($contentMarkdown);
$this->attributes['content_html'] = $converter->convert($contentMarkdown);
return $this;
}

View File

@ -23,7 +23,12 @@ use CodeIgniter\Entity\Entity;
use CodeIgniter\Files\File;
use CodeIgniter\HTTP\Files\UploadedFile;
use CodeIgniter\I18n\Time;
use League\CommonMark\CommonMarkConverter;
use League\CommonMark\Environment\Environment;
use League\CommonMark\Extension\Autolink\AutolinkExtension;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
use League\CommonMark\MarkdownConverter;
use Modules\Auth\Entities\User;
use RuntimeException;
@ -375,13 +380,21 @@ class Podcast extends Entity
public function setDescriptionMarkdown(string $descriptionMarkdown): static
{
$converter = new CommonMarkConverter([
'html_input' => 'strip',
$config = [
'html_input' => 'escape',
'allow_unsafe_links' => false,
]);
];
$environment = new Environment($config);
$environment->addExtension(new CommonMarkCoreExtension());
$environment->addExtension(new AutolinkExtension());
$environment->addExtension(new SmartPunctExtension());
$environment->addExtension(new DisallowedRawHtmlExtension());
$converter = new MarkdownConverter($environment);
$this->attributes['description_markdown'] = $descriptionMarkdown;
$this->attributes['description_html'] = $converter->convertToHtml($descriptionMarkdown);
$this->attributes['description_html'] = $converter->convert($descriptionMarkdown);
return $this;
}
@ -399,17 +412,25 @@ class Podcast extends Entity
return $this;
}
$converter = new CommonMarkConverter([
'html_input' => 'strip',
$config = [
'html_input' => 'escape',
'allow_unsafe_links' => false,
]);
];
$environment = new Environment($config);
$environment->addExtension(new CommonMarkCoreExtension());
$environment->addExtension(new AutolinkExtension());
$environment->addExtension(new SmartPunctExtension());
$environment->addExtension(new DisallowedRawHtmlExtension());
$converter = new MarkdownConverter($environment);
$this->attributes[
'episode_description_footer_markdown'
] = $episodeDescriptionFooterMarkdown;
$this->attributes[
'episode_description_footer_html'
] = $converter->convertToHtml($episodeDescriptionFooterMarkdown);
] = $converter->convert($episodeDescriptionFooterMarkdown);
return $this;
}

View File

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
if (! function_exists('form_markdown_textarea')) {
/**
* Textarea field
*
* @param mixed $data
* @param mixed $extra
*/
function form_markdown_textarea($data = '', string $value = '', $extra = ''): string
{
$defaults = [
'name' => is_array($data) ? '' : $data,
'cols' => '40',
'rows' => '10',
];
if (! is_array($data) || ! isset($data['value'])) {
$val = $value;
} else {
$val = $data['value'];
unset($data['value']); // textareas don't use the value attribute
}
// Unsets default rows and cols if defined in extra field as array or string.
if ((is_array($extra) && array_key_exists('rows', $extra)) || (is_string($extra) && stripos(
preg_replace('~\s+~', '', $extra),
'rows='
) !== false)) {
unset($defaults['rows']);
}
if ((is_array($extra) && array_key_exists('cols', $extra)) || (is_string($extra) && stripos(
preg_replace('~\s+~', '', $extra),
'cols='
) !== false)) {
unset($defaults['cols']);
}
return '<textarea ' . rtrim(parse_form_attributes($data, $defaults)) . stringify_attributes($extra) . '>'
. $val
. "</textarea>\n";
}
}

View File

@ -6,6 +6,16 @@ namespace App\Views\Components\Forms;
class MarkdownEditor extends FormComponent
{
/**
* @var string[]
*/
protected array $disallowList = [];
public function setDisallowList(string $value): void
{
$this->disallowList = explode(',', $value);
}
public function render(): string
{
$editorClass = 'w-full flex flex-col bg-elevated border-3 border-contrast rounded-lg overflow-hidden focus-within:ring-accent ' . $this->class;
@ -13,30 +23,83 @@ class MarkdownEditor extends FormComponent
$this->attributes['class'] = 'bg-elevated border-none focus:border-none focus:outline-none focus:ring-0 w-full h-full';
$this->attributes['rows'] = 6;
// dd(htmlspecialchars_decode($this->value));
$value = htmlspecialchars_decode($this->value);
$textarea = form_textarea($this->attributes, old($this->name, $value, false));
$icons = [
'heading' => icon('heading'),
'bold' => icon('bold'),
'italic' => icon('italic'),
'list-unordered' => icon('list-unordered'),
'list-ordered' => icon('list-ordered'),
'quote' => icon('quote'),
'link' => icon('link'),
'image-add' => icon('image-add'),
'markdown' => icon(
'markdown',
'mr-1 text-lg opacity-40'
),
];
$oldValue = old($this->name);
if ($oldValue === null) {
$oldValue = $value;
}
$textarea = form_textarea($this->attributes, $oldValue);
$markdownIcon = icon(
'markdown',
'mr-1 text-lg opacity-40'
);
$translations = [
'write' => lang('Common.forms.editor.write'),
'preview' => lang('Common.forms.editor.preview'),
'help' => lang('Common.forms.editor.help'),
];
$toolbarGroups = [
[
[
'name' => 'header',
'tag' => 'md-header',
'icon' => icon('heading'),
],
[
'name' => 'bold',
'tag' => 'md-bold',
'icon' => icon('bold'),
],
[
'name' => 'italic',
'tag' => 'md-italic',
'icon' => icon('italic'),
],
],
[
[
'name' => 'unordered-list',
'tag' => 'md-unordered-list',
'icon' => icon('list-unordered'),
],
[
'name' => 'ordered-list',
'tag' => 'md-ordered-list ',
'icon' => icon('list-ordered'),
],
],
[
[
'name' => 'quote',
'tag' => 'md-quote',
'icon' => icon('quote'),
],
[
'name' => 'link',
'tag' => 'md-link',
'icon' => icon('link'),
],
[
'name' => 'image',
'tag' => 'md-image',
'icon' => icon('image-add'),
],
],
];
$toolbarContent = '';
foreach ($toolbarGroups as $buttonsGroup) {
$toolbarContent .= '<div class="inline-flex text-2xl gap-x-1">';
foreach ($buttonsGroup as $button) {
if (! in_array($button['name'], $this->disallowList, true)) {
$toolbarContent .= '<' . $button['tag'] . ' class="opacity-50 hover:opacity-100 focus:ring-accent focus:opacity-100">' . $button['icon'] . '</' . $button['tag'] . '>';
}
}
$toolbarContent .= '</div>';
}
return <<<HTML
<div class="{$editorClass}">
<header class="px-2">
@ -45,22 +108,7 @@ class MarkdownEditor extends FormComponent
<button type="button" slot="write" class="px-2 font-semibold focus:ring-inset focus:ring-accent">{$translations['write']}</button>
<button type="button" slot="preview" class="px-2 font-semibold focus:ring-inset focus:ring-accent">{$translations['preview']}</button>
</markdown-write-preview>
<markdown-toolbar for="{$this->id}" class="flex gap-4 px-2 py-1">
<div class="inline-flex text-2xl gap-x-1">
<md-header class="opacity-50 hover:opacity-100 focus:ring-accent focus:opacity-100">{$icons['heading']}</md-header>
<md-bold class="opacity-50 hover:opacity-100 focus:ring-accent focus:opacity-100" data-hotkey-scope="{$this->id}" data-hotkey="Control+b,Meta+b">{$icons['bold']}</md-bold>
<md-italic class="opacity-50 hover:opacity-100 focus:ring-accent focus:opacity-100" data-hotkey-scope="{$this->id}" data-hotkey="Control+i,Meta+i">{$icons['italic']}</md-italic>
</div>
<div class="inline-flex text-2xl gap-x-1">
<md-unordered-list class="opacity-50 hover:opacity-100 focus:ring-accent focus:opacity-100">{$icons['list-unordered']}</md-unordered-list>
<md-ordered-list class="opacity-50 hover:opacity-100 focus:ring-accent focus:opacity-100">{$icons['list-ordered']}</md-ordered-list>
</div>
<div class="inline-flex text-2xl gap-x-1">
<md-quote class="opacity-50 hover:opacity-100 focus:ring-accent focus:opacity-100">{$icons['quote']}</md-quote>
<md-link class="opacity-50 hover:opacity-100 focus:ring-accent focus:opacity-100" data-hotkey-scope="{$this->id}" data-hotkey="Control+k,Meta+k">{$icons['link']}</md-link>
<md-image class="opacity-50 hover:opacity-100 focus:ring-accent focus:opacity-100">{$icons['image-add']}</md-image>
</div>
</markdown-toolbar>
<markdown-toolbar for="{$this->id}" class="flex gap-4 px-2 py-1">{$toolbarContent}</markdown-toolbar>
</div>
</header>
<div class="relative">
@ -68,7 +116,7 @@ class MarkdownEditor extends FormComponent
<markdown-preview for="{$this->id}" class="absolute top-0 left-0 hidden w-full h-full max-w-full px-3 py-2 overflow-y-auto prose bg-base" showClass="bg-elevated" />
</div>
<footer class="flex px-2 py-1 border-t bg-base">
<a href="https://commonmark.org/help/" class="inline-flex items-center text-xs font-semibold text-skin-muted hover:text-skin-base" target="_blank" rel="noopener noreferrer">{$icons['markdown']}{$translations['help']}</a>
<a href="https://commonmark.org/help/" class="inline-flex items-center text-xs font-semibold text-skin-muted hover:text-skin-base" target="_blank" rel="noopener noreferrer">{$markdownIcon}{$translations['help']}</a>
</footer>
</div>
HTML;

View File

@ -12,7 +12,7 @@
"geoip2/geoip2": "^v2.11.0",
"myth/auth": "dev-develop",
"codeigniter4/codeigniter4": "dev-develop",
"league/commonmark": "^v1.6.6",
"league/commonmark": "^2.2",
"vlucas/phpdotenv": "^v5.3.0",
"league/html-to-markdown": "^v5.0.1",
"opawg/user-agents-php": "^v1.0",

636
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": "1cd09e20009835bd1480554991ad2ff1",
"content-hash": "bf66875f72680d0f5953f03bf31c8612",
"packages": [
{
"name": "brick/math",
@ -307,6 +307,74 @@
],
"time": "2021-06-07T13:58:28+00:00"
},
{
"name": "dflydev/dot-access-data",
"version": "v3.0.1",
"source": {
"type": "git",
"url": "https://github.com/dflydev/dflydev-dot-access-data.git",
"reference": "0992cc19268b259a39e86f296da5f0677841f42c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/0992cc19268b259a39e86f296da5f0677841f42c",
"reference": "0992cc19268b259a39e86f296da5f0677841f42c",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"require-dev": {
"phpstan/phpstan": "^0.12.42",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.3",
"scrutinizer/ocular": "1.6.0",
"squizlabs/php_codesniffer": "^3.5",
"vimeo/psalm": "^3.14"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.x-dev"
}
},
"autoload": {
"psr-4": {
"Dflydev\\DotAccessData\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": ["MIT"],
"authors": [
{
"name": "Dragonfly Development Inc.",
"email": "info@dflydev.com",
"homepage": "http://dflydev.com"
},
{
"name": "Beau Simensen",
"email": "beau@dflydev.com",
"homepage": "http://beausimensen.com"
},
{
"name": "Carlos Frutos",
"email": "carlos@kiwing.it",
"homepage": "https://github.com/cfrutos"
},
{
"name": "Colin O'Dell",
"email": "colinodell@gmail.com",
"homepage": "https://www.colinodell.com"
}
],
"description": "Given a deep data structure, access data by dot notation.",
"homepage": "https://github.com/dflydev/dflydev-dot-access-data",
"keywords": ["access", "data", "dot", "notation"],
"support": {
"issues": "https://github.com/dflydev/dflydev-dot-access-data/issues",
"source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.1"
},
"time": "2021-08-13T13:06:58+00:00"
},
{
"name": "essence/dom",
"version": "1.0.0",
@ -783,40 +851,52 @@
},
{
"name": "league/commonmark",
"version": "1.6.6",
"version": "2.2.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/commonmark.git",
"reference": "c4228d11e30d7493c6836d20872f9582d8ba6dcf"
"reference": "f8afb78f087777b040e0ab8a6b6ca93f6fc3f18a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/c4228d11e30d7493c6836d20872f9582d8ba6dcf",
"reference": "c4228d11e30d7493c6836d20872f9582d8ba6dcf",
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/f8afb78f087777b040e0ab8a6b6ca93f6fc3f18a",
"reference": "f8afb78f087777b040e0ab8a6b6ca93f6fc3f18a",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": "^7.1 || ^8.0"
},
"conflict": {
"scrutinizer/ocular": "1.7.*"
"league/config": "^1.1.1",
"php": "^7.4 || ^8.0",
"psr/event-dispatcher": "^1.0",
"symfony/deprecation-contracts": "^2.1 || ^3.0",
"symfony/polyfill-php80": "^1.15"
},
"require-dev": {
"cebe/markdown": "~1.0",
"commonmark/commonmark.js": "0.29.2",
"erusev/parsedown": "~1.0",
"cebe/markdown": "^1.0",
"commonmark/cmark": "0.30.0",
"commonmark/commonmark.js": "0.30.0",
"composer/package-versions-deprecated": "^1.8",
"erusev/parsedown": "^1.0",
"ext-json": "*",
"github/gfm": "0.29.0",
"michelf/php-markdown": "~1.4",
"mikehaertl/php-shellcommand": "^1.4",
"phpstan/phpstan": "^0.12.90",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.2",
"scrutinizer/ocular": "^1.5",
"symfony/finder": "^4.2"
"michelf/php-markdown": "^1.4",
"phpstan/phpstan": "^0.12.88 || ^1.0.0",
"phpunit/phpunit": "^9.5.5",
"scrutinizer/ocular": "^1.8.1",
"symfony/finder": "^5.3",
"symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0",
"unleashedtech/php-coding-standard": "^3.1",
"vimeo/psalm": "^4.7.3"
},
"suggest": {
"symfony/yaml": "v2.3+ required if using the Front Matter extension"
},
"bin": ["bin/commonmark"],
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "2.3-dev"
}
},
"autoload": {
"psr-4": {
"League\\CommonMark\\": "src"
@ -832,7 +912,7 @@
"role": "Lead Developer"
}
],
"description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and Github-Flavored Markdown (GFM)",
"description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and GitHub-Flavored Markdown (GFM)",
"homepage": "https://commonmark.thephpleague.com",
"keywords": [
"commonmark",
@ -846,15 +926,12 @@
],
"support": {
"docs": "https://commonmark.thephpleague.com/",
"forum": "https://github.com/thephpleague/commonmark/discussions",
"issues": "https://github.com/thephpleague/commonmark/issues",
"rss": "https://github.com/thephpleague/commonmark/releases.atom",
"source": "https://github.com/thephpleague/commonmark"
},
"funding": [
{
"url": "https://enjoy.gitstore.app/repositories/thephpleague/commonmark",
"type": "custom"
},
{
"url": "https://www.colinodell.com/sponsor",
"type": "custom"
@ -867,16 +944,92 @@
"url": "https://github.com/colinodell",
"type": "github"
},
{
"url": "https://www.patreon.com/colinodell",
"type": "patreon"
},
{
"url": "https://tidelift.com/funding/github/packagist/league/commonmark",
"type": "tidelift"
}
],
"time": "2021-07-17T17:13:23+00:00"
"time": "2022-01-25T14:37:33+00:00"
},
{
"name": "league/config",
"version": "v1.1.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/config.git",
"reference": "a9d39eeeb6cc49d10a6e6c36f22c4c1f4a767f3e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/config/zipball/a9d39eeeb6cc49d10a6e6c36f22c4c1f4a767f3e",
"reference": "a9d39eeeb6cc49d10a6e6c36f22c4c1f4a767f3e",
"shasum": ""
},
"require": {
"dflydev/dot-access-data": "^3.0.1",
"nette/schema": "^1.2",
"php": "^7.4 || ^8.0"
},
"require-dev": {
"phpstan/phpstan": "^0.12.90",
"phpunit/phpunit": "^9.5.5",
"scrutinizer/ocular": "^1.8.1",
"unleashedtech/php-coding-standard": "^3.1",
"vimeo/psalm": "^4.7.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.2-dev"
}
},
"autoload": {
"psr-4": {
"League\\Config\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"authors": [
{
"name": "Colin O'Dell",
"email": "colinodell@gmail.com",
"homepage": "https://www.colinodell.com",
"role": "Lead Developer"
}
],
"description": "Define configuration arrays with strict schemas and access values with dot notation",
"homepage": "https://config.thephpleague.com",
"keywords": [
"array",
"config",
"configuration",
"dot",
"dot-access",
"nested",
"schema"
],
"support": {
"docs": "https://config.thephpleague.com/",
"issues": "https://github.com/thephpleague/config/issues",
"rss": "https://github.com/thephpleague/config/releases.atom",
"source": "https://github.com/thephpleague/config"
},
"funding": [
{
"url": "https://www.colinodell.com/sponsor",
"type": "custom"
},
{
"url": "https://www.paypal.me/colinpodell/10.00",
"type": "custom"
},
{
"url": "https://github.com/colinodell",
"type": "github"
}
],
"time": "2021-08-14T12:15:32+00:00"
},
{
"name": "league/html-to-markdown",
@ -1236,6 +1389,138 @@
],
"time": "2021-06-10T04:25:01+00:00"
},
{
"name": "nette/schema",
"version": "v1.2.2",
"source": {
"type": "git",
"url": "https://github.com/nette/schema.git",
"reference": "9a39cef03a5b34c7de64f551538cbba05c2be5df"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/schema/zipball/9a39cef03a5b34c7de64f551538cbba05c2be5df",
"reference": "9a39cef03a5b34c7de64f551538cbba05c2be5df",
"shasum": ""
},
"require": {
"nette/utils": "^2.5.7 || ^3.1.5 || ^4.0",
"php": ">=7.1 <8.2"
},
"require-dev": {
"nette/tester": "^2.3 || ^2.4",
"phpstan/phpstan-nette": "^0.12",
"tracy/tracy": "^2.7"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2-dev"
}
},
"autoload": {
"classmap": ["src/"]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause", "GPL-2.0-only", "GPL-3.0-only"],
"authors": [
{
"name": "David Grudl",
"homepage": "https://davidgrudl.com"
},
{
"name": "Nette Community",
"homepage": "https://nette.org/contributors"
}
],
"description": "📐 Nette Schema: validating data structures against a given Schema.",
"homepage": "https://nette.org",
"keywords": ["config", "nette"],
"support": {
"issues": "https://github.com/nette/schema/issues",
"source": "https://github.com/nette/schema/tree/v1.2.2"
},
"time": "2021-10-15T11:40:02+00:00"
},
{
"name": "nette/utils",
"version": "v3.2.2",
"source": {
"type": "git",
"url": "https://github.com/nette/utils.git",
"reference": "967cfc4f9a1acd5f1058d76715a424c53343c20c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/utils/zipball/967cfc4f9a1acd5f1058d76715a424c53343c20c",
"reference": "967cfc4f9a1acd5f1058d76715a424c53343c20c",
"shasum": ""
},
"require": {
"php": ">=7.2 <8.1"
},
"conflict": {
"nette/di": "<3.0.6"
},
"require-dev": {
"nette/tester": "~2.0",
"phpstan/phpstan": "^0.12",
"tracy/tracy": "^2.3"
},
"suggest": {
"ext-gd": "to use Image",
"ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()",
"ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()",
"ext-json": "to use Nette\\Utils\\Json",
"ext-mbstring": "to use Strings::lower() etc...",
"ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()",
"ext-xml": "to use Strings::length() etc. when mbstring is not available"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.2-dev"
}
},
"autoload": {
"classmap": ["src/"]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause", "GPL-2.0-only", "GPL-3.0-only"],
"authors": [
{
"name": "David Grudl",
"homepage": "https://davidgrudl.com"
},
{
"name": "Nette Community",
"homepage": "https://nette.org/contributors"
}
],
"description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.",
"homepage": "https://nette.org",
"keywords": [
"array",
"core",
"datetime",
"images",
"json",
"nette",
"paginator",
"password",
"slugify",
"string",
"unicode",
"utf-8",
"utility",
"validation"
],
"support": {
"issues": "https://github.com/nette/utils/issues",
"source": "https://github.com/nette/utils/tree/v3.2.2"
},
"time": "2021-03-03T22:53:25+00:00"
},
{
"name": "opawg/user-agents-php",
"version": "v1.0",
@ -1545,6 +1830,50 @@
},
"time": "2016-08-06T20:24:11+00:00"
},
{
"name": "psr/event-dispatcher",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/event-dispatcher.git",
"reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
"reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
"shasum": ""
},
"require": {
"php": ">=7.2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\EventDispatcher\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": ["MIT"],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Standard interfaces for event handling.",
"keywords": ["events", "psr", "psr-14"],
"support": {
"issues": "https://github.com/php-fig/event-dispatcher/issues",
"source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0"
},
"time": "2019-01-08T18:20:26+00:00"
},
{
"name": "psr/log",
"version": "1.1.4",
@ -1741,6 +2070,69 @@
],
"time": "2020-08-18T17:17:46+00:00"
},
{
"name": "symfony/deprecation-contracts",
"version": "v2.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5f38c8804a9e97d23e0c8d63341088cd8a22d627",
"reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "2.4-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
},
"autoload": {
"files": ["function.php"]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["MIT"],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v2.4.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2021-03-23T23:28:01+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.23.0",
@ -2787,85 +3179,6 @@
},
"time": "2021-02-28T12:30:32+00:00"
},
{
"name": "nette/utils",
"version": "v3.2.2",
"source": {
"type": "git",
"url": "https://github.com/nette/utils.git",
"reference": "967cfc4f9a1acd5f1058d76715a424c53343c20c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/utils/zipball/967cfc4f9a1acd5f1058d76715a424c53343c20c",
"reference": "967cfc4f9a1acd5f1058d76715a424c53343c20c",
"shasum": ""
},
"require": {
"php": ">=7.2 <8.1"
},
"conflict": {
"nette/di": "<3.0.6"
},
"require-dev": {
"nette/tester": "~2.0",
"phpstan/phpstan": "^0.12",
"tracy/tracy": "^2.3"
},
"suggest": {
"ext-gd": "to use Image",
"ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()",
"ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()",
"ext-json": "to use Nette\\Utils\\Json",
"ext-mbstring": "to use Strings::lower() etc...",
"ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()",
"ext-xml": "to use Strings::length() etc. when mbstring is not available"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.2-dev"
}
},
"autoload": {
"classmap": ["src/"]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause", "GPL-2.0-only", "GPL-3.0-only"],
"authors": [
{
"name": "David Grudl",
"homepage": "https://davidgrudl.com"
},
{
"name": "Nette Community",
"homepage": "https://nette.org/contributors"
}
],
"description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.",
"homepage": "https://nette.org",
"keywords": [
"array",
"core",
"datetime",
"images",
"json",
"nette",
"paginator",
"password",
"slugify",
"string",
"unicode",
"utf-8",
"utility",
"validation"
],
"support": {
"issues": "https://github.com/nette/utils/issues",
"source": "https://github.com/nette/utils/tree/v3.2.2"
},
"time": "2021-03-03T22:53:25+00:00"
},
{
"name": "nikic/php-parser",
"version": "v4.10.5",
@ -3838,50 +4151,6 @@
},
"time": "2021-03-05T17:36:06+00:00"
},
{
"name": "psr/event-dispatcher",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/event-dispatcher.git",
"reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
"reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
"shasum": ""
},
"require": {
"php": ">=7.2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\EventDispatcher\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": ["MIT"],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Standard interfaces for event handling.",
"keywords": ["events", "psr", "psr-14"],
"support": {
"issues": "https://github.com/php-fig/event-dispatcher/issues",
"source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0"
},
"time": "2019-01-08T18:20:26+00:00"
},
{
"name": "rector/rector",
"version": "0.11.16",
@ -5271,69 +5540,6 @@
],
"time": "2021-05-26T17:57:12+00:00"
},
{
"name": "symfony/deprecation-contracts",
"version": "v2.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5f38c8804a9e97d23e0c8d63341088cd8a22d627",
"reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "2.4-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
},
"autoload": {
"files": ["function.php"]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["MIT"],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v2.4.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2021-03-23T23:28:01+00:00"
},
{
"name": "symfony/error-handler",
"version": "v5.3.0",

View File

@ -118,13 +118,15 @@
as="MarkdownEditor"
name="description"
label="<?= lang('Episode.form.description') ?>"
required="true" />
required="true"
disallowList="header,quote" />
<Forms.Field
as="MarkdownEditor"
name="description_footer"
label="<?= lang('Episode.form.description_footer') ?>"
hint="<?= lang('Episode.form.description_footer_hint') ?>" />
hint="<?= lang('Episode.form.description_footer_hint') ?>"
disallowList="header,quote" />
</Forms.Section>

View File

@ -123,14 +123,16 @@
name="description"
label="<?= lang('Episode.form.description') ?>"
value="<?= htmlspecialchars($episode->description_markdown) ?>"
required="true" />
required="true"
disallowList="header,quote" />
<Forms.Field
as="MarkdownEditor"
name="description_footer"
label="<?= lang('Episode.form.description_footer') ?>"
hint="<?= lang('Episode.form.description_footer_hint') ?>"
value="<?= htmlspecialchars($podcast->episode_description_footer_markdown) ?? '' ?>" />
value="<?= htmlspecialchars($podcast->episode_description_footer_markdown) ?? '' ?>"
disallowList="header,quote" />
</Forms.Section>

View File

@ -53,7 +53,8 @@
as="MarkdownEditor"
name="description"
label="<?= lang('Podcast.form.description') ?>"
required="true" />
required="true"
disallowList="header,quote" />
<fieldset>
<legend><?= lang('Podcast.form.type.label') ?></legend>

View File

@ -68,7 +68,8 @@
name="description"
label="<?= lang('Podcast.form.description') ?>"
value="<?= htmlspecialchars($podcast->description_markdown) ?>"
required="true" />
required="true"
disallowList="header,quote" />
<fieldset>
<legend><?= lang('Podcast.form.type.label') ?></legend>