mirror of
https://github.com/Karaka-Management/phpOMS.git
synced 2026-02-08 05:18:40 +00:00
add tests + some new markdown functionality
This commit is contained in:
parent
36b7143829
commit
bbb9d06f29
|
|
@ -32,6 +32,23 @@ use phpOMS\Uri\UriFactory;
|
||||||
* @see https://github.com/BenjaminHoegh/ParsedownExtended
|
* @see https://github.com/BenjaminHoegh/ParsedownExtended
|
||||||
* @see https://github.com/doowzs/parsedown-extreme
|
* @see https://github.com/doowzs/parsedown-extreme
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
|
*
|
||||||
|
* @todo: Add
|
||||||
|
* 2. Calendar (own widget)
|
||||||
|
* 3. Event (own widget)
|
||||||
|
* 4. Tasks (own widget)
|
||||||
|
* 5. Vote/Survey (own widget)
|
||||||
|
* 6. Website link/embed widgets (facebook, linkedIn, twitter, ...)
|
||||||
|
* 7. User/Supplier/Client/Employee (own widget, should make use of schema)
|
||||||
|
* 8. Address (own widget, should make use of schema)
|
||||||
|
* 9. Contact (own widget, should make use of schema)
|
||||||
|
* 10. Item (own widget, should make use of schema)
|
||||||
|
* 11. Progress radial
|
||||||
|
* 12. Timeline horizontal/vertical/matrix
|
||||||
|
* 14. Tabs horizontal/vertical
|
||||||
|
* 15. Checklist (own widget)
|
||||||
|
* 16. Gallery
|
||||||
|
* 17. Form (own widget)
|
||||||
*/
|
*/
|
||||||
class Markdown
|
class Markdown
|
||||||
{
|
{
|
||||||
|
|
@ -70,7 +87,7 @@ class Markdown
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
protected array $underlineRegex = [
|
protected array $underlineRegex = [
|
||||||
'_' => '/^__((?:\\\\_|[^_]|_[^_]*+_)+?)__(?!_)/us',
|
'_' => '/^[_]{2}((?:\\\\\_|[^_]|[_][^_]_+[_])+?)[_]{2}(?![_])/s',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -81,7 +98,6 @@ class Markdown
|
||||||
*/
|
*/
|
||||||
protected array $emRegex = [
|
protected array $emRegex = [
|
||||||
'*' => '/^[*]((?:\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s',
|
'*' => '/^[*]((?:\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s',
|
||||||
'_' => '/^_((?:\\\\_|[^_]|__[^_]*__)+?)_(?!_)\b/us',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -275,7 +291,7 @@ class Markdown
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
private const CONTINUABLE = [
|
private const CONTINUABLE = [
|
||||||
'Code', 'Comment', 'FencedCode', 'List', 'Quote', 'Table', 'Math', 'Checkbox', 'Footnote', 'DefinitionList', 'Markup'
|
'Code', 'Comment', 'FencedCode', 'List', 'Quote', 'Table', 'Math', 'Spoiler', 'Checkbox', 'Footnote', 'DefinitionList', 'Markup'
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -285,7 +301,7 @@ class Markdown
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
private const COMPLETABLE = [
|
private const COMPLETABLE = [
|
||||||
'Math', 'Table', 'Checkbox', 'Footnote', 'Markup', 'Code', 'FencedCode', 'List'
|
'Math', 'Spoiler', 'Table', 'Checkbox', 'Footnote', 'Markup', 'Code', 'FencedCode', 'List'
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -424,7 +440,7 @@ class Markdown
|
||||||
|
|
||||||
// Marks
|
// Marks
|
||||||
if ($this->options['mark'] ?? true) {
|
if ($this->options['mark'] ?? true) {
|
||||||
$this->inlineTypes['='][] = 'mark';
|
$this->inlineTypes['='][] = 'Mark';
|
||||||
$this->inlineMarkerList .= '=';
|
$this->inlineMarkerList .= '=';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -434,6 +450,12 @@ class Markdown
|
||||||
$this->inlineMarkerList .= '[';
|
$this->inlineMarkerList .= '[';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Spoiler
|
||||||
|
if ($this->options['spoiler'] ?? false) {
|
||||||
|
$this->inlineTypes['>'][] = 'Spoiler';
|
||||||
|
$this->inlineMarkerList .= '=';
|
||||||
|
}
|
||||||
|
|
||||||
// Inline Math
|
// Inline Math
|
||||||
if ($this->options['math'] ?? false) {
|
if ($this->options['math'] ?? false) {
|
||||||
$this->inlineTypes['\\'][] = 'Math';
|
$this->inlineTypes['\\'][] = 'Math';
|
||||||
|
|
@ -473,32 +495,19 @@ class Markdown
|
||||||
$this->inlineMarkerList .= '?';
|
$this->inlineMarkerList .= '?';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Smartypants
|
|
||||||
if ($this->options['smarty'] ?? false) {
|
|
||||||
$this->inlineTypes['<'][] = 'Smartypants';
|
|
||||||
$this->inlineMarkerList .= '<';
|
|
||||||
$this->inlineTypes['>'][] = 'Smartypants';
|
|
||||||
$this->inlineMarkerList .= '>';
|
|
||||||
$this->inlineTypes['-'][] = 'Smartypants';
|
|
||||||
$this->inlineMarkerList .= '-';
|
|
||||||
$this->inlineTypes['.'][] = 'Smartypants';
|
|
||||||
$this->inlineMarkerList .= '.';
|
|
||||||
$this->inlineTypes["'"][] = 'Smartypants';
|
|
||||||
$this->inlineMarkerList .= "'";
|
|
||||||
$this->inlineTypes['"'][] = 'Smartypants';
|
|
||||||
$this->inlineMarkerList .= '"';
|
|
||||||
$this->inlineTypes['`'][] = 'Smartypants';
|
|
||||||
$this->inlineMarkerList .= '`';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Block Math
|
// Block Math
|
||||||
if ($this->options['math'] ?? false) {
|
if ($this->options['math'] ?? false) {
|
||||||
$this->blockTypes['\\'][] = 'Math';
|
$this->blockTypes['\\'][] = 'Math';
|
||||||
$this->blockTypes['$'][] = 'Math';
|
$this->blockTypes['$'][] = 'Math';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Task
|
// Block Spoiler
|
||||||
if ($this->options['lists']['tasks'] ?? true) {
|
if ($this->options['spoiler'] ?? false) {
|
||||||
|
$this->blockTypes['?'][] = 'Spoiler';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checkbox
|
||||||
|
if ($this->options['lists']['checkbox'] ?? true) {
|
||||||
$this->blockTypes['['][] = 'Checkbox';
|
$this->blockTypes['['][] = 'Checkbox';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -507,6 +516,24 @@ class Markdown
|
||||||
$this->inlineTypes['['][] = 'Embeding';
|
$this->inlineTypes['['][] = 'Embeding';
|
||||||
$this->inlineMarkerList .= '[';
|
$this->inlineMarkerList .= '[';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Map
|
||||||
|
if ($this->options['map'] ?? false) {
|
||||||
|
$this->inlineTypes['['][] = 'Map';
|
||||||
|
$this->inlineMarkerList .= '[';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Address
|
||||||
|
if ($this->options['address'] ?? false) {
|
||||||
|
$this->inlineTypes['['][] = 'Address';
|
||||||
|
$this->inlineMarkerList .= '[';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contact
|
||||||
|
if ($this->options['contact'] ?? false) {
|
||||||
|
$this->inlineTypes['['][] = 'Contact';
|
||||||
|
$this->inlineMarkerList .= '[';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -518,7 +545,7 @@ class Markdown
|
||||||
*
|
*
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
public static function parse($text) : string
|
public static function parse(string $text) : string
|
||||||
{
|
{
|
||||||
$parsedown = new self();
|
$parsedown = new self();
|
||||||
|
|
||||||
|
|
@ -1205,6 +1232,30 @@ class Markdown
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle marks
|
||||||
|
*
|
||||||
|
* @param array{text:string, context:string, before:string} $excerpt Inline data
|
||||||
|
*
|
||||||
|
* @return null|array{extent:int, element:array}
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
protected function inlineSpoiler(array $excerpt) : ?array
|
||||||
|
{
|
||||||
|
if (\preg_match('/^>!(.*?)!</us', $excerpt['text'], $matches) !== 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'extent' => \strlen($matches[0]),
|
||||||
|
'element' => [
|
||||||
|
'name' => 'mark',
|
||||||
|
'text' => $matches[2],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle keystrokes
|
* Handle keystrokes
|
||||||
*
|
*
|
||||||
|
|
@ -1322,6 +1373,232 @@ class Markdown
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle map
|
||||||
|
*
|
||||||
|
* @param array{text:string, context:string, before:string} $excerpt Inline data
|
||||||
|
*
|
||||||
|
* @return null|array{extent:int, element:array}
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
protected function inlineMap(array $excerpt) : ?array
|
||||||
|
{
|
||||||
|
if (!($this->options['map'] ?? false)
|
||||||
|
|| (\preg_match('/\[map(?:\s+(?:name="([^"]+)"|country="([^"]+)"|city="([^"]+)"|zip="([^"]+)"|address="([^"]+)"|lat="([^"]+)"|lon="([^"]+)")){0,3}\]/', $excerpt['text'], $matches) !== 1)
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = $matches[1];
|
||||||
|
$country = $matches[2];
|
||||||
|
$city = $matches[3];
|
||||||
|
$zip = $matches[4];
|
||||||
|
$address = $matches[5];
|
||||||
|
|
||||||
|
$lat = empty($matches[6]) ? '' : (float) $matches[6];
|
||||||
|
$lon = empty($matches[7]) ? '' : (float) $matches[7];
|
||||||
|
|
||||||
|
if ($lat === '' || $lon === '') {
|
||||||
|
[$lat, $lon] = \phpOMS\Api\Geocoding\Nominatim::geocoding($country, $city, $address, $zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'extent' => \strlen($matches[0]),
|
||||||
|
'element' => [
|
||||||
|
'name' => 'div',
|
||||||
|
'text' => '',
|
||||||
|
'attributes' => [
|
||||||
|
'id' => '-' . \bin2hex(\random_bytes(4)),
|
||||||
|
'class' => 'map',
|
||||||
|
'data-lat' => $lat,
|
||||||
|
'data-lon' => $lon,
|
||||||
|
]
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle address
|
||||||
|
*
|
||||||
|
* @param array{text:string, context:string, before:string} $excerpt Inline data
|
||||||
|
*
|
||||||
|
* @return null|array{extent:int, element:array}
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
protected function inlineAddress(array $excerpt) : ?array
|
||||||
|
{
|
||||||
|
if (!($this->options['address'] ?? false)
|
||||||
|
|| (\preg_match('/\[addr(?:\s+(?:name="([^"]+)"|country="([^"]+)"|city="([^"]+)"|zip="([^"]+)"|address="([^"]+)")){0,3}\]/', $excerpt['text'], $matches) !== 1)
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = $matches[1];
|
||||||
|
$country = $matches[2];
|
||||||
|
$city = $matches[3];
|
||||||
|
$zip = $matches[4];
|
||||||
|
$address = $matches[5];
|
||||||
|
|
||||||
|
return [
|
||||||
|
'extent' => \strlen($matches[0]),
|
||||||
|
'element' => [
|
||||||
|
'name' => 'div',
|
||||||
|
//'text' => '',
|
||||||
|
'attributes' => [
|
||||||
|
'class' => 'addressWidget',
|
||||||
|
],
|
||||||
|
'elements' => [
|
||||||
|
[
|
||||||
|
'name' => 'span',
|
||||||
|
'text' => $name,
|
||||||
|
'attributes' => ['class' => 'addressWidget-name'],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'span',
|
||||||
|
'text' => $address,
|
||||||
|
'attributes' => ['class' => 'addressWidget-address'],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'span',
|
||||||
|
'text' => $zip,
|
||||||
|
'attributes' => ['class' => 'addressWidget-zip'],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'span',
|
||||||
|
'text' => $city,
|
||||||
|
'attributes' => ['class' => 'addressWidget-city'],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'span',
|
||||||
|
'text' => $country,
|
||||||
|
'attributes' => ['class' => 'addressWidget-country'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle contact
|
||||||
|
*
|
||||||
|
* @param array{text:string, context:string, before:string} $excerpt Inline data
|
||||||
|
*
|
||||||
|
* @return null|array{extent:int, element:array}
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
protected function inlineContact(array $excerpt) : ?array
|
||||||
|
{
|
||||||
|
if (!($this->options['contact'] ?? false)
|
||||||
|
|| (\preg_match('/\[contact.*?([a-zA-Z]+)="([a-zA-Z0-9\-_]+)"\]/', $excerpt['text'], $matches) !== 1)
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$src = '';
|
||||||
|
switch ($matches[1]) {
|
||||||
|
case 'email':
|
||||||
|
$src = 'Resources/icons/company/email.svg';
|
||||||
|
break;
|
||||||
|
case 'phone':
|
||||||
|
$src = 'Resources/icons/company/phone.svg';
|
||||||
|
break;
|
||||||
|
case 'twitter':
|
||||||
|
$src = 'Resources/icons/company/twitter.svg';
|
||||||
|
break;
|
||||||
|
case 'instagram':
|
||||||
|
$src = 'Resources/icons/company/instagram.svg';
|
||||||
|
break;
|
||||||
|
case 'discord':
|
||||||
|
$src = 'Resources/icons/company/discord.svg';
|
||||||
|
break;
|
||||||
|
case 'slack':
|
||||||
|
$src = 'Resources/icons/company/slack.svg';
|
||||||
|
break;
|
||||||
|
case 'teams':
|
||||||
|
$src = 'Resources/icons/company/teams.svg';
|
||||||
|
break;
|
||||||
|
case 'facebook':
|
||||||
|
$src = 'Resources/icons/company/facebook.svg';
|
||||||
|
break;
|
||||||
|
case 'youtube':
|
||||||
|
$src = 'Resources/icons/company/youtube.svg';
|
||||||
|
break;
|
||||||
|
case 'paypal':
|
||||||
|
$src = 'Resources/icons/company/paypal.svg';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'extent' => \strlen($matches[0]),
|
||||||
|
'element' => [
|
||||||
|
'name' => 'a',
|
||||||
|
//'text' => '',
|
||||||
|
'attributes' => [
|
||||||
|
'class' => 'contactWidget',
|
||||||
|
'href' => '',
|
||||||
|
],
|
||||||
|
'elements' => [
|
||||||
|
[
|
||||||
|
'name' => 'img',
|
||||||
|
'attributes' => [
|
||||||
|
'class' => 'contactWidget-icon',
|
||||||
|
'src' => $src
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'span',
|
||||||
|
'text' => $matches[2],
|
||||||
|
'attributes' => ['class' => 'contactWidget-contact'],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle progress
|
||||||
|
*
|
||||||
|
* @param array{text:string, context:string, before:string} $excerpt Inline data
|
||||||
|
*
|
||||||
|
* @return null|array{extent:int, element:array}
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
protected function inlineProgress(array $excerpt) : ?array
|
||||||
|
{
|
||||||
|
if (!($this->options['progress'] ?? false)
|
||||||
|
|| (\preg_match('/\[progress(?:\s+(?:type="([^"]+)"|percent="([^"]+)"|value="([^"]+)")){0,3}\]/', $excerpt['text'], $matches) !== 1)
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// $type = $matches[1] ?? 'meter';
|
||||||
|
$percent = $matches[2] ?? ($matches[3]);
|
||||||
|
$value = $matches[3] ?? $matches[2];
|
||||||
|
|
||||||
|
if ($percent === ''
|
||||||
|
|| $value === ''
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'extent' => \strlen($matches[0]),
|
||||||
|
'element' => [
|
||||||
|
'name' => 'progress',
|
||||||
|
//'text' => '',
|
||||||
|
'attributes' => [
|
||||||
|
'value' => $value,
|
||||||
|
'max' => '100',
|
||||||
|
]
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle super script
|
* Handle super script
|
||||||
*
|
*
|
||||||
|
|
@ -1406,140 +1683,6 @@ class Markdown
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle smartypants
|
|
||||||
*
|
|
||||||
* @param array{text:string, context:string, before:string} $excerpt Inline data
|
|
||||||
*
|
|
||||||
* @return null|array{extent:int, element:array}
|
|
||||||
*
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
protected function inlineSmartypants(array $excerpt) : ?array
|
|
||||||
{
|
|
||||||
if (\preg_match('/(``)(?!\s)([^"\'`]{1,})(\'\')|(\")(?!\s)([^\"]{1,})(\")|(\')(?!\s)([^\']{1,})(\')|(<{2})(?!\s)([^<>]{1,})(>{2})|(\.{3})|(-{3})|(-{2})/i', $excerpt['text'], $matches) !== 1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Substitutions
|
|
||||||
$backtickDoublequoteOpen = $this->options['smarty']['substitutions']['left-double-quote'] ?? '“';
|
|
||||||
$backtickDoublequoteClose = $this->options['smarty']['substitutions']['right-double-quote'] ?? '”';
|
|
||||||
|
|
||||||
$smartDoublequoteOpen = $this->options['smarty']['substitutions']['left-double-quote'] ?? '“';
|
|
||||||
$smartDoublequoteClose = $this->options['smarty']['substitutions']['right-double-quote'] ?? '”';
|
|
||||||
$smartSinglequoteOpen = $this->options['smarty']['substitutions']['left-single-quote'] ?? '‘';
|
|
||||||
$smartSinglequoteClose = $this->options['smarty']['substitutions']['right-single-quote'] ?? '’';
|
|
||||||
|
|
||||||
$leftAngleQuote = $this->options['smarty']['substitutions']['left-angle-quote'] ?? '«';
|
|
||||||
$rightAngleQuote = $this->options['smarty']['substitutions']['right-angle-quote'] ?? '»';
|
|
||||||
|
|
||||||
$matches = \array_values(\array_filter($matches));
|
|
||||||
|
|
||||||
// Smart backticks
|
|
||||||
$smartBackticks = $this->options['smarty']['smart_backticks'] ?? false;
|
|
||||||
|
|
||||||
if ($smartBackticks && $matches[1] === '``') {
|
|
||||||
$length = \strlen(\trim($excerpt['before']));
|
|
||||||
if ($length > 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
'extent' => \strlen($matches[0]),
|
|
||||||
'element' => [
|
|
||||||
'text' => \html_entity_decode($backtickDoublequoteOpen).$matches[2].\html_entity_decode($backtickDoublequoteClose),
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Smart quotes
|
|
||||||
$smartQuotes = $this->options['smarty']['smart_quotes'] ?? true;
|
|
||||||
|
|
||||||
if ($smartQuotes) {
|
|
||||||
if ($matches[1] === "'") {
|
|
||||||
$length = \strlen(\trim($excerpt['before']));
|
|
||||||
if ($length > 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
'extent' => \strlen($matches[0]),
|
|
||||||
'element' => [
|
|
||||||
'text' => \html_entity_decode($smartSinglequoteOpen).$matches[2].\html_entity_decode($smartSinglequoteClose),
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($matches[1] === '"') {
|
|
||||||
$length = \strlen(\trim($excerpt['before']));
|
|
||||||
if ($length > 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
'extent' => \strlen($matches[0]),
|
|
||||||
'element' => [
|
|
||||||
'text' => \html_entity_decode($smartDoublequoteOpen).$matches[2].\html_entity_decode($smartDoublequoteClose),
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Smart angled quotes
|
|
||||||
$smartAngledQuotes = $this->options['smarty']['smart_angled_quotes'] ?? true;
|
|
||||||
|
|
||||||
if ($smartAngledQuotes && $matches[1] === '<<') {
|
|
||||||
$length = \strlen(\trim($excerpt['before']));
|
|
||||||
if ($length > 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
'extent' => \strlen($matches[0]),
|
|
||||||
'element' => [
|
|
||||||
'text' => \html_entity_decode($leftAngleQuote).$matches[2].\html_entity_decode($rightAngleQuote),
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Smart dashes
|
|
||||||
$smartDashes = $this->options['smarty']['smart_dashes'] ?? true;
|
|
||||||
|
|
||||||
if ($smartDashes) {
|
|
||||||
if ($matches[1] === '---') {
|
|
||||||
return [
|
|
||||||
'extent' => \strlen($matches[0]),
|
|
||||||
'element' => [
|
|
||||||
'rawHtml' => $this->options['smarty']['substitutions']['mdash'] ?? '—',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($matches[1] === '--') {
|
|
||||||
return [
|
|
||||||
'extent' => \strlen($matches[0]),
|
|
||||||
'element' => [
|
|
||||||
'rawHtml' => $this->options['smarty']['substitutions']['ndash'] ?? '–',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Smart ellipses
|
|
||||||
$smartEllipses = $this->options['smarty']['smart_ellipses'] ?? true;
|
|
||||||
|
|
||||||
if ($smartEllipses && $matches[1] === '...') {
|
|
||||||
return [
|
|
||||||
'extent' => \strlen($matches[0]),
|
|
||||||
'element' => [
|
|
||||||
'rawHtml' => $this->options['smarty']['substitutions']['ellipses'] ?? '…',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle math
|
* Handle math
|
||||||
*
|
*
|
||||||
|
|
@ -1832,7 +1975,7 @@ class Markdown
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
list($name, $pattern) = $line['text'][0] <= '-' ? ['ul', '[*+-]'] : ['ol', '[0-9]{1,9}+[.\)]'];
|
[$name, $pattern] = $line['text'][0] <= '-' ? ['ul', '[*+-]'] : ['ol', '[0-9]{1,9}+[.\)]'];
|
||||||
|
|
||||||
if (\preg_match('/^(' . $pattern . '([ ]++|$))(.*+)/', $line['text'], $matches) !== 1) {
|
if (\preg_match('/^(' . $pattern . '([ ]++|$))(.*+)/', $line['text'], $matches) !== 1) {
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -2320,6 +2463,7 @@ class Markdown
|
||||||
|
|
||||||
return $block;
|
return $block;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (\preg_match('/^(?<!\\\\)(\$\$)$/', $line['text']) && $block['end'] === '$$') {
|
if (\preg_match('/^(?<!\\\\)(\$\$)$/', $line['text']) && $block['end'] === '$$') {
|
||||||
$block['complete'] = true;
|
$block['complete'] = true;
|
||||||
$block['math'] = true;
|
$block['math'] = true;
|
||||||
|
|
@ -2457,6 +2601,57 @@ class Markdown
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Continue block spoiler
|
||||||
|
*
|
||||||
|
* @param array{body:string, indent:int, text:string} $line Line data
|
||||||
|
* @param null|array $_ Current block (unused parameter)
|
||||||
|
*
|
||||||
|
* @return null|array
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
protected function blockSpoiler(array $line, array $_ = null) : ?array
|
||||||
|
{
|
||||||
|
if (!($this->options['code']['blocks'] ?? true)
|
||||||
|
|| !($this->options['code'] ?? true)
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$marker = $line['text'][0];
|
||||||
|
$openerLength = \strspn($line['text'], $marker);
|
||||||
|
|
||||||
|
if ($openerLength < 3) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$summary = \trim(\preg_replace('/^\?{3}([^\s]+)(.+)?/s', '$1', $line['text']));
|
||||||
|
|
||||||
|
$infostring = \trim(\substr($line['text'], $openerLength), "\t ");
|
||||||
|
if (\strpos($infostring, '?') !== false) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'char' => $marker,
|
||||||
|
'openerLength' => $openerLength,
|
||||||
|
'element' => [
|
||||||
|
'name' => 'details',
|
||||||
|
'elements' => [
|
||||||
|
[
|
||||||
|
'name' => 'summary',
|
||||||
|
'text' => $summary,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'span', // @todo: check if without span possible
|
||||||
|
'text' => '',
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Complete block table
|
* Complete block table
|
||||||
*
|
*
|
||||||
|
|
@ -2639,9 +2834,13 @@ class Markdown
|
||||||
*/
|
*/
|
||||||
protected function blockCheckboxComplete(array $block) : array
|
protected function blockCheckboxComplete(array $block) : array
|
||||||
{
|
{
|
||||||
|
if ($this->markupEscaped || $this->safeMode) {
|
||||||
|
$text = \htmlspecialchars($block['text'], \ENT_QUOTES, 'UTF-8');
|
||||||
|
}
|
||||||
|
|
||||||
$html = $block['handler'] === 'unchecked'
|
$html = $block['handler'] === 'unchecked'
|
||||||
? $this->checkboxUnchecked($block['text'])
|
? '<input type="checkbox" disabled /> ' . $this->formatOnce($text)
|
||||||
: $this->checkboxChecked($block['text']);
|
: '<input type="checkbox" checked disabled /> ' . $this->formatOnce($text);
|
||||||
|
|
||||||
$block['element'] = [
|
$block['element'] = [
|
||||||
'rawHtml' => $html,
|
'rawHtml' => $html,
|
||||||
|
|
@ -2651,42 +2850,6 @@ class Markdown
|
||||||
return $block;
|
return $block;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate unchecked checkbox html
|
|
||||||
*
|
|
||||||
* @param string Checkbox text
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
protected function checkboxUnchecked(string $text) : string
|
|
||||||
{
|
|
||||||
if ($this->markupEscaped || $this->safeMode) {
|
|
||||||
$text = \htmlspecialchars($text, \ENT_QUOTES, 'UTF-8');
|
|
||||||
}
|
|
||||||
|
|
||||||
return '<input type="checkbox" disabled /> ' . $this->formatOnce($text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate checked checkbox html
|
|
||||||
*
|
|
||||||
* @param string Checkbox text
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
protected function checkboxChecked(string $text) : string
|
|
||||||
{
|
|
||||||
if ($this->markupEscaped || $this->safeMode) {
|
|
||||||
$text = \htmlspecialchars($text, \ENT_QUOTES, 'UTF-8');
|
|
||||||
}
|
|
||||||
|
|
||||||
return '<input type="checkbox" checked disabled /> ' . $this->formatOnce($text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats text without double escaping
|
* Formats text without double escaping
|
||||||
*
|
*
|
||||||
|
|
@ -3259,24 +3422,21 @@ class Markdown
|
||||||
|
|
||||||
++$this->definitionData['Footnote'][$name]['count'];
|
++$this->definitionData['Footnote'][$name]['count'];
|
||||||
|
|
||||||
if (!isset($this->definitionData['Footnote'][$name]['number']))
|
if (!isset($this->definitionData['Footnote'][$name]['number'])) {
|
||||||
{
|
|
||||||
$this->definitionData['Footnote'][$name]['number'] = ++ $this->footnoteCount; // » &
|
$this->definitionData['Footnote'][$name]['number'] = ++ $this->footnoteCount; // » &
|
||||||
}
|
}
|
||||||
|
|
||||||
$element = [
|
|
||||||
'name' => 'sup',
|
|
||||||
'attributes' => ['id' => 'fnref' . $this->definitionData['Footnote'][$name]['count'] . ':' . $name],
|
|
||||||
'element' => [
|
|
||||||
'name' => 'a',
|
|
||||||
'attributes' => ['href' => '#fn:' . $name, 'class' => 'footnote-ref'],
|
|
||||||
'text' => $this->definitionData['Footnote'][$name]['number'],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'extent' => \strlen($matches[0]),
|
'extent' => \strlen($matches[0]),
|
||||||
'element' => $element,
|
'element' => [
|
||||||
|
'name' => 'sup',
|
||||||
|
'attributes' => ['id' => 'fnref' . $this->definitionData['Footnote'][$name]['count'] . ':' . $name],
|
||||||
|
'element' => [
|
||||||
|
'name' => 'a',
|
||||||
|
'attributes' => ['href' => '#fn:' . $name, 'class' => 'footnote-ref'],
|
||||||
|
'text' => $this->definitionData['Footnote'][$name]['number'],
|
||||||
|
],
|
||||||
|
]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3848,6 +4008,57 @@ class Markdown
|
||||||
return $block;
|
return $block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Continue block spoiler
|
||||||
|
*
|
||||||
|
* @param array{body:string, indent:int, text:string} $line Line data
|
||||||
|
* @param array $block Current block
|
||||||
|
*
|
||||||
|
* @return null|array
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
protected function blockSpoilerContinue(array $line, array $block) : ?array
|
||||||
|
{
|
||||||
|
if (isset($block['complete'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($block['interrupted'])) {
|
||||||
|
$block['element']['element']['text'] .= \str_repeat("\n", $block['interrupted']);
|
||||||
|
|
||||||
|
unset($block['interrupted']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($len = \strspn($line['text'], $block['char'])) >= $block['openerLength']
|
||||||
|
&& \rtrim(\substr($line['text'], $len), ' ') === ''
|
||||||
|
) {
|
||||||
|
$block['element']['element']['text'] = \substr($block['element']['element']['text'], 1);
|
||||||
|
|
||||||
|
$block['complete'] = true;
|
||||||
|
|
||||||
|
return $block;
|
||||||
|
}
|
||||||
|
|
||||||
|
$block['element']['element']['text'] .= "\n" . $line['body'];
|
||||||
|
|
||||||
|
return $block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Complete block spoiler
|
||||||
|
*
|
||||||
|
* @param array $block Current block
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
protected function blockSpoilerComplete(array $block) : array
|
||||||
|
{
|
||||||
|
return $block;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Continue block list
|
* Continue block list
|
||||||
*
|
*
|
||||||
|
|
@ -4130,10 +4341,10 @@ class Markdown
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$Definition = $this->definitionData['Reference'][$definition];
|
$definition = $this->definitionData['Reference'][$definition];
|
||||||
|
|
||||||
$element['attributes']['href'] = $Definition['url'];
|
$element['attributes']['href'] = $definition['url'];
|
||||||
$element['attributes']['title'] = $Definition['title'];
|
$element['attributes']['title'] = $definition['title'];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,95 @@ final class MarkdownTest extends \PHPUnit\Framework\TestCase
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testMap() : void
|
||||||
|
{
|
||||||
|
$parser = new Markdown([
|
||||||
|
'map' => true
|
||||||
|
]);
|
||||||
|
|
||||||
|
self::assertEquals(
|
||||||
|
\file_get_contents(__DIR__ . '/manualdata/map.html'),
|
||||||
|
$parser->text(\file_get_contents(__DIR__ . '/manualdata/map.md'))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testContact() : void
|
||||||
|
{
|
||||||
|
$parser = new Markdown([
|
||||||
|
'contact' => true
|
||||||
|
]);
|
||||||
|
|
||||||
|
self::assertEquals(
|
||||||
|
\file_get_contents(__DIR__ . '/manualdata/contact.html'),
|
||||||
|
$parser->text(\file_get_contents(__DIR__ . '/manualdata/contact.md'))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTypographer() : void
|
||||||
|
{
|
||||||
|
$parser = new Markdown([
|
||||||
|
'typographer' => true
|
||||||
|
]);
|
||||||
|
|
||||||
|
self::assertEquals(
|
||||||
|
\file_get_contents(__DIR__ . '/manualdata/typographer.html'),
|
||||||
|
$parser->text(\file_get_contents(__DIR__ . '/manualdata/typographer.md'))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAddress() : void
|
||||||
|
{
|
||||||
|
$parser = new Markdown([
|
||||||
|
'address' => true
|
||||||
|
]);
|
||||||
|
|
||||||
|
self::assertEquals(
|
||||||
|
\file_get_contents(__DIR__ . '/manualdata/address.html'),
|
||||||
|
$parser->text(\file_get_contents(__DIR__ . '/manualdata/address.md'))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProgress() : void
|
||||||
|
{
|
||||||
|
$parser = new Markdown([
|
||||||
|
'progress' => true
|
||||||
|
]);
|
||||||
|
|
||||||
|
self::assertEquals(
|
||||||
|
\file_get_contents(__DIR__ . '/manualdata/progress.html'),
|
||||||
|
$parser->text(\file_get_contents(__DIR__ . '/manualdata/progress.md'))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSpoiler() : void
|
||||||
|
{
|
||||||
|
$parser = new Markdown([
|
||||||
|
'spoiler' => true
|
||||||
|
]);
|
||||||
|
|
||||||
|
self::assertEquals(
|
||||||
|
\file_get_contents(__DIR__ . '/manualdata/spoiler.html'),
|
||||||
|
$parser->text(\file_get_contents(__DIR__ . '/manualdata/spoiler.md'))
|
||||||
|
);
|
||||||
|
|
||||||
|
self::assertEquals(
|
||||||
|
\file_get_contents(__DIR__ . '/manualdata/spoiler_block.html'),
|
||||||
|
$parser->text(\file_get_contents(__DIR__ . '/manualdata/spoiler_block.md'))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEmbed() : void
|
||||||
|
{
|
||||||
|
$parser = new Markdown([
|
||||||
|
'embeding' => true
|
||||||
|
]);
|
||||||
|
|
||||||
|
self::assertEquals(
|
||||||
|
\file_get_contents(__DIR__ . '/manualdata/embed.html'),
|
||||||
|
$parser->text(\file_get_contents(__DIR__ . '/manualdata/embed.md'))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function testMath() : void
|
public function testMath() : void
|
||||||
{
|
{
|
||||||
$parser = new Markdown([
|
$parser = new Markdown([
|
||||||
|
|
|
||||||
0
tests/Utils/Parser/Markdown/data/checkbox.htm
Normal file
0
tests/Utils/Parser/Markdown/data/checkbox.htm
Normal file
2
tests/Utils/Parser/Markdown/data/checkbox.md
Normal file
2
tests/Utils/Parser/Markdown/data/checkbox.md
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
- [ ] Unchecked
|
||||||
|
- [x] Checked
|
||||||
1
tests/Utils/Parser/Markdown/data/emoji.html
Normal file
1
tests/Utils/Parser/Markdown/data/emoji.html
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
📹
|
||||||
1
tests/Utils/Parser/Markdown/data/emoji.md
Normal file
1
tests/Utils/Parser/Markdown/data/emoji.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
:video_camera:
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<p><em>underscore</em>, <em>asterisk</em>, <em>one two</em>, <em>three four</em>, <em>a</em>, <em>b</em></p>
|
<p><u>underscore</u>, <em>asterisk</em>, <em>one two</em>, <em>three four</em>, <em>a</em>, <em>b</em></p>
|
||||||
<p><strong>strong</strong> and <em>em</em> and <strong>strong</strong> and <em>em</em></p>
|
<p><strong>strong</strong> and <em>em</em> and <strong>strong</strong> and <em>em</em></p>
|
||||||
<p><em>line
|
<p><em>line
|
||||||
line
|
line
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
_underscore_, *asterisk*, _one two_, *three four*, _a_, *b*
|
__underscore__, *asterisk*, _one two_, *three four*, _a_, *b*
|
||||||
|
|
||||||
**strong** and *em* and **strong** and *em*
|
**strong** and *em* and **strong** and *em*
|
||||||
|
|
||||||
|
|
|
||||||
1
tests/Utils/Parser/Markdown/data/keystroke.html
Normal file
1
tests/Utils/Parser/Markdown/data/keystroke.html
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<kbd>ctrl</kbd>+<kbd>shift</kbd>+<kbd>A</kbd>
|
||||||
1
tests/Utils/Parser/Markdown/data/keystroke.md
Normal file
1
tests/Utils/Parser/Markdown/data/keystroke.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
[[ctrl]] + [[shift]] + [[A]]
|
||||||
1
tests/Utils/Parser/Markdown/data/mark.html
Normal file
1
tests/Utils/Parser/Markdown/data/mark.html
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<mark>Mark test</mark>
|
||||||
1
tests/Utils/Parser/Markdown/data/mark.md
Normal file
1
tests/Utils/Parser/Markdown/data/mark.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
==Mark test==
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
[video src="https://www.youtube.com/watch?v=dQw4w9WgXcQ&ab_channel=RickAstley"]
|
|
||||||
1
tests/Utils/Parser/Markdown/manualdata/address.html
Normal file
1
tests/Utils/Parser/Markdown/manualdata/address.html
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
[addr name="AddrName" address="Addr" city="AddrCity" country="AddrCoutry" zip="AddrZip"]
|
||||||
1
tests/Utils/Parser/Markdown/manualdata/address.md
Normal file
1
tests/Utils/Parser/Markdown/manualdata/address.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
[addr name="AddrName" address="Addr" city="AddrCity" country="AddrCoutry" zip="AddrZip"]
|
||||||
9
tests/Utils/Parser/Markdown/manualdata/contact.html
Normal file
9
tests/Utils/Parser/Markdown/manualdata/contact.html
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
[contact phone="+49 123 456 789"]
|
||||||
|
[contact facebook="@jinggaApp"]
|
||||||
|
[contact discord="jingga"]
|
||||||
|
[contact email="test@email.com"]
|
||||||
|
[contact twitter="@jinggaApp"]
|
||||||
|
[contact youtube="@jinggaApp"]
|
||||||
|
[contact instagram="jinggaApp"]
|
||||||
|
[contact slack="jinggaApp"]
|
||||||
|
[contact teams="jinggaApp"]
|
||||||
9
tests/Utils/Parser/Markdown/manualdata/contact.md
Normal file
9
tests/Utils/Parser/Markdown/manualdata/contact.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
[contact phone="+49 123 456 789"]
|
||||||
|
[contact facebook="@jinggaApp"]
|
||||||
|
[contact discord="jingga"]
|
||||||
|
[contact email="test@email.com"]
|
||||||
|
[contact twitter="@jinggaApp"]
|
||||||
|
[contact youtube="@jinggaApp"]
|
||||||
|
[contact instagram="jinggaApp"]
|
||||||
|
[contact slack="jinggaApp"]
|
||||||
|
[contact teams="jinggaApp"]
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
<p>[video src="<a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ&ab_channel=RickAstley">https://www.youtube.com/watch?v=dQw4w9WgXcQ&ab_channel=RickAstley</a>"]</p>
|
<p>[video src="<a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ&ab_channel=RickAstley">https://www.youtube.com/watch?v=dQw4w9WgXcQ&ab_channel=RickAstley</a>"]</p>
|
||||||
|
<video src="test.mp4"></video>
|
||||||
4
tests/Utils/Parser/Markdown/manualdata/embed.md
Normal file
4
tests/Utils/Parser/Markdown/manualdata/embed.md
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
[video src="https://www.youtube.com/watch?v=dQw4w9WgXcQ&ab_channel=RickAstley"]
|
||||||
|
[video src="https://vimeo.com/874474957"]
|
||||||
|
[video src="https://www.dailymotion.com/video/x3w7rss"]
|
||||||
|
[video src="test.mp4"]
|
||||||
1
tests/Utils/Parser/Markdown/manualdata/map.html
Normal file
1
tests/Utils/Parser/Markdown/manualdata/map.html
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<div id="" class="map" data-lat="1.0" data-lon="1.0"></div>
|
||||||
1
tests/Utils/Parser/Markdown/manualdata/map.md
Normal file
1
tests/Utils/Parser/Markdown/manualdata/map.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
[map lat="1.0" lon="1.0"]
|
||||||
1
tests/Utils/Parser/Markdown/manualdata/progress.html
Normal file
1
tests/Utils/Parser/Markdown/manualdata/progress.html
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<progress value="33" max="100"></progress>
|
||||||
1
tests/Utils/Parser/Markdown/manualdata/progress.md
Normal file
1
tests/Utils/Parser/Markdown/manualdata/progress.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
[progress value="33"]
|
||||||
1
tests/Utils/Parser/Markdown/manualdata/spoiler.html
Normal file
1
tests/Utils/Parser/Markdown/manualdata/spoiler.html
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
This is a >!test spoiler!< in text.
|
||||||
1
tests/Utils/Parser/Markdown/manualdata/spoiler.md
Normal file
1
tests/Utils/Parser/Markdown/manualdata/spoiler.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
This is a >!test spoiler!< in text.
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
<details><summary>Test summary</summary><span>This is a test spoiler.</span></details>
|
||||||
3
tests/Utils/Parser/Markdown/manualdata/spoiler_block.md
Normal file
3
tests/Utils/Parser/Markdown/manualdata/spoiler_block.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
???Test summary
|
||||||
|
This is a test spoiler.
|
||||||
|
???
|
||||||
1
tests/Utils/Parser/Markdown/manualdata/typographer.html
Normal file
1
tests/Utils/Parser/Markdown/manualdata/typographer.html
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
©
|
||||||
1
tests/Utils/Parser/Markdown/manualdata/typographer.md
Normal file
1
tests/Utils/Parser/Markdown/manualdata/typographer.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
(c)
|
||||||
Loading…
Reference in New Issue
Block a user