mirror of
https://github.com/Karaka-Management/phpOMS.git
synced 2026-02-07 13:08:40 +00:00
started with markdown formatting
This commit is contained in:
parent
9018cf5b57
commit
4645d59b8a
|
|
@ -29,50 +29,70 @@ use phpOMS\Uri\UriFactory;
|
||||||
*/
|
*/
|
||||||
class Markdown
|
class Markdown
|
||||||
{
|
{
|
||||||
# ~
|
/**
|
||||||
|
* Parsedown version
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
public const version = '1.8.0-beta-7';
|
public const version = '1.8.0-beta-7';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parsing options
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
private array $options = [];
|
private array $options = [];
|
||||||
|
|
||||||
# ~
|
/**
|
||||||
|
* Table of content id
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
private string $idToc = '';
|
private string $idToc = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param array $params Parameters
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
public function __construct(array $params = [])
|
public function __construct(array $params = [])
|
||||||
{
|
{
|
||||||
$this->options = $params;
|
$this->options = $params;
|
||||||
|
|
||||||
$this->options['toc'] = $this->options['toc'] ?? false;
|
$this->options['toc'] = $this->options['toc'] ?? false;
|
||||||
|
|
||||||
// Marks
|
// Marks
|
||||||
$state = $this->options['mark'] ?? true;
|
$state = $this->options['mark'] ?? true;
|
||||||
if ($state !== false) {
|
if ($state !== false) {
|
||||||
$this->InlineTypes['='][] = 'mark';
|
$this->InlineTypes['='][] = 'mark';
|
||||||
$this->inlineMarkerList .= '=';
|
$this->inlineMarkerList .= '=';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keystrokes
|
// Keystrokes
|
||||||
$state = $this->options['keystrokes'] ?? true;
|
$state = $this->options['keystrokes'] ?? true;
|
||||||
if ($state !== false) {
|
if ($state !== false) {
|
||||||
$this->InlineTypes['['][] = 'Keystrokes';
|
$this->InlineTypes['['][] = 'Keystrokes';
|
||||||
$this->inlineMarkerList .= '[';
|
$this->inlineMarkerList .= '[';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline Math
|
// Inline Math
|
||||||
$state = $this->options['math'] ?? false;
|
$state = $this->options['math'] ?? false;
|
||||||
if ($state !== false) {
|
if ($state !== false) {
|
||||||
$this->InlineTypes['\\'][] = 'Math';
|
$this->InlineTypes['\\'][] = 'Math';
|
||||||
$this->inlineMarkerList .= '\\';
|
$this->inlineMarkerList .= '\\';
|
||||||
$this->InlineTypes['$'][] = 'Math';
|
$this->InlineTypes['$'][] = 'Math';
|
||||||
$this->inlineMarkerList .= '$';
|
$this->inlineMarkerList .= '$';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Superscript
|
// Superscript
|
||||||
$state = $this->options['sup'] ?? false;
|
$state = $this->options['sup'] ?? false;
|
||||||
if ($state !== false) {
|
if ($state !== false) {
|
||||||
$this->InlineTypes['^'][] = 'Superscript';
|
$this->InlineTypes['^'][] = 'Superscript';
|
||||||
$this->inlineMarkerList .= '^';
|
$this->inlineMarkerList .= '^';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscript
|
// Subscript
|
||||||
|
|
@ -85,48 +105,43 @@ class Markdown
|
||||||
$state = $this->options['emojis'] ?? true;
|
$state = $this->options['emojis'] ?? true;
|
||||||
if ($state !== false) {
|
if ($state !== false) {
|
||||||
$this->InlineTypes[':'][] = 'Emojis';
|
$this->InlineTypes[':'][] = 'Emojis';
|
||||||
$this->inlineMarkerList .= ':';
|
$this->inlineMarkerList .= ':';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Typographer
|
// Typographer
|
||||||
$state = $this->options['typographer'] ?? false;
|
$state = $this->options['typographer'] ?? false;
|
||||||
if ($state !== false) {
|
if ($state !== false) {
|
||||||
$this->InlineTypes['('][] = 'Typographer';
|
$this->InlineTypes['('][] = 'Typographer';
|
||||||
$this->inlineMarkerList .= '(';
|
$this->inlineMarkerList .= '(';
|
||||||
$this->InlineTypes['.'][] = 'Typographer';
|
$this->InlineTypes['.'][] = 'Typographer';
|
||||||
$this->inlineMarkerList .= '.';
|
$this->inlineMarkerList .= '.';
|
||||||
$this->InlineTypes['+'][] = 'Typographer';
|
$this->InlineTypes['+'][] = 'Typographer';
|
||||||
$this->inlineMarkerList .= '+';
|
$this->inlineMarkerList .= '+';
|
||||||
$this->InlineTypes['!'][] = 'Typographer';
|
$this->InlineTypes['!'][] = 'Typographer';
|
||||||
$this->inlineMarkerList .= '!';
|
$this->inlineMarkerList .= '!';
|
||||||
$this->InlineTypes['?'][] = 'Typographer';
|
$this->InlineTypes['?'][] = 'Typographer';
|
||||||
$this->inlineMarkerList .= '?';
|
$this->inlineMarkerList .= '?';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Smartypants
|
// Smartypants
|
||||||
$state = $this->options['smarty'] ?? false;
|
$state = $this->options['smarty'] ?? false;
|
||||||
if ($state !== false) {
|
if ($state !== false) {
|
||||||
$this->InlineTypes['<'][] = 'Smartypants';
|
$this->InlineTypes['<'][] = 'Smartypants';
|
||||||
$this->inlineMarkerList .= '<';
|
$this->inlineMarkerList .= '<';
|
||||||
$this->InlineTypes['>'][] = 'Smartypants';
|
$this->InlineTypes['>'][] = 'Smartypants';
|
||||||
$this->inlineMarkerList .= '>';
|
$this->inlineMarkerList .= '>';
|
||||||
$this->InlineTypes['-'][] = 'Smartypants';
|
$this->InlineTypes['-'][] = 'Smartypants';
|
||||||
$this->inlineMarkerList .= '-';
|
$this->inlineMarkerList .= '-';
|
||||||
$this->InlineTypes['.'][] = 'Smartypants';
|
$this->InlineTypes['.'][] = 'Smartypants';
|
||||||
$this->inlineMarkerList .= '.';
|
$this->inlineMarkerList .= '.';
|
||||||
$this->InlineTypes["'"][] = 'Smartypants';
|
$this->InlineTypes["'"][] = 'Smartypants';
|
||||||
$this->inlineMarkerList .= "'";
|
$this->inlineMarkerList .= "'";
|
||||||
$this->InlineTypes['"'][] = 'Smartypants';
|
$this->InlineTypes['"'][] = 'Smartypants';
|
||||||
$this->inlineMarkerList .= '"';
|
$this->inlineMarkerList .= '"';
|
||||||
$this->InlineTypes['`'][] = 'Smartypants';
|
$this->InlineTypes['`'][] = 'Smartypants';
|
||||||
$this->inlineMarkerList .= '`';
|
$this->inlineMarkerList .= '`';
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Blocks
|
|
||||||
* ------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Block Math
|
// Block Math
|
||||||
$state = $this->options['math'] ?? false;
|
$state = $this->options['math'] ?? false;
|
||||||
if ($state !== false) {
|
if ($state !== false) {
|
||||||
|
|
@ -141,26 +156,18 @@ class Markdown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function textParent($text)
|
public function textParent($text) : string
|
||||||
{
|
{
|
||||||
$Elements = $this->textElements($text);
|
$Elements = $this->textElements($text);
|
||||||
|
$markup = $this->elements($Elements);
|
||||||
|
$markup = \trim($markup, "\n");
|
||||||
|
|
||||||
# convert to markup
|
// Merge consecutive dl elements
|
||||||
$markup = $this->elements($Elements);
|
|
||||||
|
|
||||||
# trim line breaks
|
|
||||||
$markup = \trim($markup, "\n");
|
|
||||||
|
|
||||||
# merge consecutive dl elements
|
|
||||||
|
|
||||||
$markup = \preg_replace('/<\/dl>\s+<dl>\s+/', '', $markup);
|
$markup = \preg_replace('/<\/dl>\s+<dl>\s+/', '', $markup);
|
||||||
|
|
||||||
# add footnotes
|
// Add footnotes
|
||||||
|
if (isset($this->DefinitionData['Footnote'])) {
|
||||||
if (isset($this->DefinitionData['Footnote']))
|
|
||||||
{
|
|
||||||
$Element = $this->buildFootnoteElement();
|
$Element = $this->buildFootnoteElement();
|
||||||
|
|
||||||
$markup .= "\n" . $this->element($Element);
|
$markup .= "\n" . $this->element($Element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -168,13 +175,18 @@ class Markdown
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the given markdown string to an HTML string but it leaves the ToC
|
* Parses the given markdown string to an HTML string but it ignores ToC
|
||||||
* tag as is. It's an alias of the parent method "\DynamicParent::text()".
|
*
|
||||||
|
* @param string $text Markdown text to parse
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
public function body($text) : string
|
public function body(string $text) : string
|
||||||
{
|
{
|
||||||
$text = $this->encodeTagToHash($text); // Escapes ToC tag temporary
|
$text = $this->encodeTagToHash($text); // Escapes ToC tag temporary
|
||||||
$html = $this->textParent($text); // Parses the markdown text
|
$html = $this->textParent($text); // Parses the markdown text
|
||||||
|
|
||||||
return $this->decodeTagFromHash($html); // Unescape the ToC tag
|
return $this->decodeTagFromHash($html); // Unescape the ToC tag
|
||||||
}
|
}
|
||||||
|
|
@ -183,7 +195,7 @@ class Markdown
|
||||||
* Parses markdown string to HTML and also the "[toc]" tag as well.
|
* Parses markdown string to HTML and also the "[toc]" tag as well.
|
||||||
* It overrides the parent method: \Parsedown::text().
|
* It overrides the parent method: \Parsedown::text().
|
||||||
*/
|
*/
|
||||||
public function text($text)
|
public function text($text) : string
|
||||||
{
|
{
|
||||||
// Parses the markdown text except the ToC tag. This also searches
|
// Parses the markdown text except the ToC tag. This also searches
|
||||||
// the list of contents and available to get from "contentsList()"
|
// the list of contents and available to get from "contentsList()"
|
||||||
|
|
@ -194,6 +206,7 @@ class Markdown
|
||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle toc
|
||||||
$tagOrigin = $this->getTagToC();
|
$tagOrigin = $this->getTagToC();
|
||||||
|
|
||||||
if (\strpos($text, $tagOrigin) === false) {
|
if (\strpos($text, $tagOrigin) === false) {
|
||||||
|
|
@ -202,8 +215,8 @@ class Markdown
|
||||||
|
|
||||||
$tocData = $this->contentsList();
|
$tocData = $this->contentsList();
|
||||||
$tocId = $this->getIdAttributeToC();
|
$tocId = $this->getIdAttributeToC();
|
||||||
$needle = '<p>'.$tagOrigin.'</p>';
|
$needle = '<p>' . $tagOrigin . '</p>';
|
||||||
$replace = "<div id=\"{$tocId}\">{$tocData}</div>";
|
$replace = '<div id="' . $tocId . '">' . $tocData . '</div>';
|
||||||
|
|
||||||
return \str_replace($needle, $replace, $html);
|
return \str_replace($needle, $replace, $html);
|
||||||
}
|
}
|
||||||
|
|
@ -214,8 +227,10 @@ class Markdown
|
||||||
* @param string $typeReturn Type of the return format. "html" or "json".
|
* @param string $typeReturn Type of the return format. "html" or "json".
|
||||||
*
|
*
|
||||||
* @return string HTML/JSON string of ToC
|
* @return string HTML/JSON string of ToC
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
public function contentsList($typeReturn = 'html')
|
public function contentsList($typeReturn = 'html') : string
|
||||||
{
|
{
|
||||||
if (\strtolower($typeReturn) === 'html') {
|
if (\strtolower($typeReturn) === 'html') {
|
||||||
$result = '';
|
$result = '';
|
||||||
|
|
@ -225,121 +240,127 @@ class Markdown
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
} elseif (\strtolower($typeReturn) === 'json') {
|
||||||
|
|
||||||
if (\strtolower($typeReturn) === 'json') {
|
|
||||||
return \json_encode($this->contentsListArray);
|
return \json_encode($this->contentsListArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forces to return ToC as "html"
|
|
||||||
\error_log(
|
|
||||||
'Unknown return type given while parsing ToC.'
|
|
||||||
.' At: '.__FUNCTION__.'() '
|
|
||||||
.' in Line:'.__LINE__.' (Using default type)'
|
|
||||||
);
|
|
||||||
|
|
||||||
return $this->contentsList('html');
|
return $this->contentsList('html');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ------------------------------------------------------------------------
|
* Handle inline code
|
||||||
* Inline
|
*
|
||||||
* ------------------------------------------------------------------------.
|
* @param array{text:string, context:string, before:string} $excerpt Inline data
|
||||||
|
*
|
||||||
|
* @return null|array
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
|
protected function inlineCode(array $excerpt) : ?array
|
||||||
// inlineCode
|
|
||||||
protected function inlineCode($Excerpt)
|
|
||||||
{
|
{
|
||||||
$codeSnippets = $this->options['code']['inline'] ?? true;
|
if (($this->options['code']['inline'] ?? true) !== true
|
||||||
$codeMain = $this->options['code'] ?? true;
|
|| ($this->options['code'] ?? true) !== true
|
||||||
|
) {
|
||||||
if ($codeSnippets !== true || $codeMain !== true) {
|
return null;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$marker = $Excerpt['text'][0];
|
$marker = $excerpt['text'][0];
|
||||||
|
|
||||||
if (\preg_match('/^(['.$marker.']++)[ ]*+(.+?)[ ]*+(?<!['.$marker.'])\1(?!'.$marker.')/s', $Excerpt['text'], $matches))
|
if (\preg_match(
|
||||||
{
|
'/^([' . $marker . ']++)[ ]*+(.+?)[ ]*+(?<![' . $marker . '])\1(?!' . $marker . ')/s',
|
||||||
$text = $matches[2];
|
$excerpt['text'], $matches
|
||||||
$text = \preg_replace('/[ ]*+\n/', ' ', $text);
|
) !== 1
|
||||||
|
) {
|
||||||
return [
|
return null;
|
||||||
'extent' => \strlen($matches[0]),
|
|
||||||
'element' => [
|
|
||||||
'name' => 'code',
|
|
||||||
'text' => $text,
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$text = $matches[2];
|
||||||
|
$text = \preg_replace('/[ ]*+\n/', ' ', $text);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'extent' => \strlen($matches[0]),
|
||||||
|
'element' => [
|
||||||
|
'name' => 'code',
|
||||||
|
'text' => $text,
|
||||||
|
],
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function inlineEmailTag($Excerpt)
|
/**
|
||||||
|
* Handle inline email
|
||||||
|
*
|
||||||
|
* @param array{text:string, context:string, before:string} $excerpt Inline data
|
||||||
|
*
|
||||||
|
* @return null|array
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
protected function inlineEmailTag(array $excerpt) : ?array
|
||||||
{
|
{
|
||||||
$mainState = $this->options['links'] ?? true;
|
if (!($this->options['links'] ?? true)
|
||||||
$state = $this->options['links']['email_links'] ?? true;
|
|| !($this->options['links']['email_links'] ?? true)
|
||||||
|
) {
|
||||||
if (!$mainState || !$state) {
|
return null;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$hostnameLabel = '[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?';
|
$hostnameLabel = '[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?';
|
||||||
|
$commonMarkEmail = '[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]++@' . $hostnameLabel . '(?:\.' . $hostnameLabel . ')*';
|
||||||
|
|
||||||
$commonMarkEmail = '[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]++@'
|
if (\strpos($excerpt['text'], '>') === false
|
||||||
. $hostnameLabel . '(?:\.' . $hostnameLabel . ')*';
|
|| \preg_match('/^<((mailto:)?{' . $commonMarkEmail . '})>/i', $excerpt['text'], $matches) !== 1
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (\strpos($Excerpt['text'], '>') !== false
|
$url = UriFactory::build($matches[1]);
|
||||||
&& \preg_match("/^<((mailto:)?{$commonMarkEmail})>/i", $Excerpt['text'], $matches)
|
|
||||||
){
|
|
||||||
$url = UriFactory::build($matches[1]);
|
|
||||||
|
|
||||||
if (!isset($matches[2]))
|
if (!isset($matches[2])) {
|
||||||
{
|
$url = "mailto:{$url}";
|
||||||
$url = "mailto:{$url}";
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'extent' => \strlen($matches[0]),
|
'extent' => \strlen($matches[0]),
|
||||||
'element' => [
|
'element' => [
|
||||||
'name' => 'a',
|
'name' => 'a',
|
||||||
'text' => $matches[1],
|
'text' => $matches[1],
|
||||||
'attributes' => [
|
'attributes' => [
|
||||||
'href' => $url,
|
'href' => $url,
|
||||||
],
|
|
||||||
],
|
],
|
||||||
];
|
],
|
||||||
}
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function inlineEmphasis($Excerpt)
|
/**
|
||||||
|
* Inline emphasis
|
||||||
|
*
|
||||||
|
* @param array{text:string, context:string, before:string} $excerpt Inline data
|
||||||
|
*
|
||||||
|
* @return null|array
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
protected function inlineEmphasis(array $excerpt) : ?array
|
||||||
{
|
{
|
||||||
$state = $this->options['emphasis'] ?? true;
|
if (!($this->options['emphasis'] ?? true)
|
||||||
if (!$state) {
|
|| !isset($excerpt['text'][1])
|
||||||
return;
|
) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($Excerpt['text'][1]))
|
$marker = $excerpt['text'][0];
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$marker = $Excerpt['text'][0];
|
if ($excerpt['text'][1] === $marker
|
||||||
|
&& isset($this->StrongRegex[$marker]) && \preg_match($this->StrongRegex[$marker], $excerpt['text'], $matches)
|
||||||
if ($Excerpt['text'][1] === $marker && isset($this->StrongRegex[$marker]) && \preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches))
|
) {
|
||||||
{
|
|
||||||
$emphasis = 'strong';
|
$emphasis = 'strong';
|
||||||
}
|
} elseif ($excerpt['text'][1] === $marker
|
||||||
elseif ($Excerpt['text'][1] === $marker && isset($this->UnderlineRegex[$marker]) && \preg_match($this->UnderlineRegex[$marker], $Excerpt['text'], $matches))
|
&& isset($this->UnderlineRegex[$marker]) && \preg_match($this->UnderlineRegex[$marker], $excerpt['text'], $matches)
|
||||||
{
|
) {
|
||||||
$emphasis = 'u';
|
$emphasis = 'u';
|
||||||
}
|
} elseif (\preg_match($this->EmRegex[$marker], $excerpt['text'], $matches)) {
|
||||||
elseif (\preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches))
|
|
||||||
{
|
|
||||||
$emphasis = 'em';
|
$emphasis = 'em';
|
||||||
}
|
} else {
|
||||||
else
|
return null;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
@ -355,161 +376,169 @@ class Markdown
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function inlineImage($Excerpt)
|
/**
|
||||||
|
* Handle image
|
||||||
|
*
|
||||||
|
* @param array{text:string, context:string, before:string} $excerpt Inline data
|
||||||
|
*
|
||||||
|
* @return null|array
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
protected function inlineImage(array $excerpt) : ?array
|
||||||
{
|
{
|
||||||
$state = $this->options['images'] ?? true;
|
if (!($this->options['images'] ?? true)
|
||||||
if (!$state) {
|
|| !isset($excerpt['text'][1]) || $excerpt['text'][1] !== '['
|
||||||
return;
|
) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($Excerpt['text'][1]) || $Excerpt['text'][1] !== '[')
|
$excerpt['text'] = \substr($excerpt['text'], 1);
|
||||||
{
|
$link = $this->inlineLink($excerpt);
|
||||||
return;
|
|
||||||
|
if ($link === null) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$Excerpt['text']= \substr($Excerpt['text'], 1);
|
$inline = [
|
||||||
|
'extent' => $link['extent'] + 1,
|
||||||
$Link = $this->inlineLink($Excerpt);
|
|
||||||
|
|
||||||
if ($Link === null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$Inline = [
|
|
||||||
'extent' => $Link['extent'] + 1,
|
|
||||||
'element' => [
|
'element' => [
|
||||||
'name' => 'img',
|
'name' => 'img',
|
||||||
'attributes' => [
|
'attributes' => [
|
||||||
'src' => $Link['element']['attributes']['href'],
|
'src' => $link['element']['attributes']['href'],
|
||||||
'alt' => $Link['element']['handler']['argument'],
|
'alt' => $link['element']['handler']['argument'],
|
||||||
],
|
],
|
||||||
'autobreak' => true,
|
'autobreak' => true,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$Inline['element']['attributes'] += $Link['element']['attributes'];
|
$inline['element']['attributes'] += $link['element']['attributes'];
|
||||||
|
|
||||||
unset($Inline['element']['attributes']['href']);
|
unset($inline['element']['attributes']['href']);
|
||||||
|
|
||||||
return $Inline;
|
return $inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function inlineLink($Excerpt)
|
/**
|
||||||
|
* Handle link
|
||||||
|
*
|
||||||
|
* @param array{text:string, context:string, before:string} $excerpt Inline data
|
||||||
|
*
|
||||||
|
* @return null|array
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
protected function inlineLink(array $excerpt) : ?array
|
||||||
{
|
{
|
||||||
$state = $this->options['links'] ?? true;
|
if (!($this->options['links'] ?? true)) {
|
||||||
if (!$state) {
|
return null;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$Link = $this->inlineLinkParent($Excerpt);
|
$link = $this->inlineLinkParent($excerpt);
|
||||||
|
$remainder = $link !== null ? \substr($excerpt['text'], $link['extent']) : '';
|
||||||
|
|
||||||
$remainder = $Link !== null ? \substr($Excerpt['text'], $Link['extent']) : '';
|
if (\preg_match('/^[ ]*{(' . $this->regexAttribute . '+)}/', $remainder, $matches)) {
|
||||||
|
$link['element']['attributes'] += $this->parseAttributeData($matches[1]);
|
||||||
if (\preg_match('/^[ ]*{('.$this->regexAttribute.'+)}/', $remainder, $matches))
|
$link['extent'] += \strlen($matches[0]);
|
||||||
{
|
|
||||||
$Link['element']['attributes'] += $this->parseAttributeData($matches[1]);
|
|
||||||
|
|
||||||
$Link['extent'] += \strlen($matches[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $Link;
|
return $link;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function inlineMarkup($Excerpt)
|
/**
|
||||||
|
* Handle markup
|
||||||
|
*
|
||||||
|
* @param array{text:string, context:string, before:string} $excerpt Inline data
|
||||||
|
*
|
||||||
|
* @return null|array
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
protected function inlineMarkup(array $excerpt) : ?array
|
||||||
{
|
{
|
||||||
$state = $this->options['markup'] ?? true;
|
if (!($this->options['markup'] ?? true)
|
||||||
if (!$state) {
|
|| $this->markupEscaped || $this->safeMode || \strpos($excerpt['text'], '>') === false
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->markupEscaped || $this->safeMode || \strpos($Excerpt['text'], '>') === false)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($Excerpt['text'][1] === '/' && \preg_match('/^<\/\w[\w-]*+[ ]*+>/s', $Excerpt['text'], $matches))
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'element' => ['rawHtml' => $matches[0]],
|
|
||||||
'extent' => \strlen($matches[0]),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($Excerpt['text'][1] === '!' && \preg_match('/^<!---?[^>-](?:-?+[^-])*-->/s', $Excerpt['text'], $matches))
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'element' => ['rawHtml' => $matches[0]],
|
|
||||||
'extent' => \strlen($matches[0]),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($Excerpt['text'][1] !== ' ' && \preg_match('/^<\w[\w-]*+(?:[ ]*+'.$this->regexHtmlAttribute.')*+[ ]*+\/?>/s', $Excerpt['text'], $matches))
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'element' => ['rawHtml' => $matches[0]],
|
|
||||||
'extent' => \strlen($matches[0]),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function inlineStrikethrough($Excerpt)
|
|
||||||
{
|
|
||||||
$state = $this->options['strikethroughs'] ?? true;
|
|
||||||
if (!$state) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($Excerpt['text'][1]))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($Excerpt['text'][1] === '~' && \preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $Excerpt['text'], $matches))
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'extent' => \strlen($matches[0]),
|
|
||||||
'element' => [
|
|
||||||
'name' => 'del',
|
|
||||||
'handler' => [
|
|
||||||
'function' => 'lineElements',
|
|
||||||
'argument' => $matches[1],
|
|
||||||
'destination' => 'elements',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function inlineUrl($Excerpt)
|
|
||||||
{
|
|
||||||
$state = $this->options['links'] ?? true;
|
|
||||||
if (!$state) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->urlsLinked !== true || !isset($Excerpt['text'][2]) || $Excerpt['text'][2] !== '/')
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (\strpos($Excerpt['context'], 'http') !== false
|
|
||||||
&& \preg_match('/\bhttps?+:[\/]{2}[^\s<]+\b\/*+/ui', $Excerpt['context'], $matches, \PREG_OFFSET_CAPTURE)
|
|
||||||
) {
|
) {
|
||||||
$url = UriFactory::build($matches[0][0]);
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($excerpt['text'][1] === '/' && \preg_match('/^<\/\w[\w-]*+[ ]*+>/s', $excerpt['text'], $matches))
|
||||||
|
|| ($excerpt['text'][1] === '!' && \preg_match('/^<!---?[^>-](?:-?+[^-])*-->/s', $excerpt['text'], $matches))
|
||||||
|
|| ($excerpt['text'][1] !== ' ' && \preg_match('/^<\w[\w-]*+(?:[ ]*+' . $this->regexHtmlAttribute . ')*+[ ]*+\/?>/s', $excerpt['text'], $matches))
|
||||||
|
) {
|
||||||
return [
|
return [
|
||||||
'extent' => \strlen($matches[0][0]),
|
'element' => ['rawHtml' => $matches[0]],
|
||||||
'position' => $matches[0][1],
|
'extent' => \strlen($matches[0]),
|
||||||
'element' => [
|
|
||||||
'name' => 'a',
|
|
||||||
'text' => $url,
|
|
||||||
'attributes' => [
|
|
||||||
'href' => $url,
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle striketrhough
|
||||||
|
*
|
||||||
|
* @param array{text:string, context:string, before:string} $excerpt Inline data
|
||||||
|
*
|
||||||
|
* @return null|array
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
protected function inlineStrikethrough($excerpt) : ?array
|
||||||
|
{
|
||||||
|
if (!($this->options['strikethroughs'] ?? true)
|
||||||
|
|| !isset($excerpt['text'][1])
|
||||||
|
|| $excerpt['text'][1] !== '~'
|
||||||
|
|| \preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $excerpt['text'], $matches) !== 1
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'extent' => \strlen($matches[0]),
|
||||||
|
'element' => [
|
||||||
|
'name' => 'del',
|
||||||
|
'handler' => [
|
||||||
|
'function' => 'lineElements',
|
||||||
|
'argument' => $matches[1],
|
||||||
|
'destination' => 'elements',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle url
|
||||||
|
*
|
||||||
|
* @param array{text:string, context:string, before:string} $excerpt Inline data
|
||||||
|
*
|
||||||
|
* @return null|array
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
protected function inlineUrl($excerpt) : ?array
|
||||||
|
{
|
||||||
|
if (!($this->options['links'] ?? true)
|
||||||
|
|| $this->urlsLinked !== true || !isset($excerpt['text'][2]) || $excerpt['text'][2] !== '/'
|
||||||
|
|| \strpos($excerpt['context'], 'http') === false
|
||||||
|
|| \preg_match('/\bhttps?+:[\/]{2}[^\s<]+\b\/*+/ui', $excerpt['context'], $matches, \PREG_OFFSET_CAPTURE) !== 1
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$url = UriFactory::build($matches[0][0]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'extent' => \strlen($matches[0][0]),
|
||||||
|
'position' => $matches[0][1],
|
||||||
|
'element' => [
|
||||||
|
'name' => 'a',
|
||||||
|
'text' => $url,
|
||||||
|
'attributes' => [
|
||||||
|
'href' => $url,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function inlineUrlTag($Excerpt)
|
protected function inlineUrlTag($Excerpt)
|
||||||
|
|
@ -1847,24 +1876,22 @@ class Markdown
|
||||||
{
|
{
|
||||||
$Elements = [];
|
$Elements = [];
|
||||||
|
|
||||||
$nonNestables = (
|
$nonNestables = empty($nonNestables)
|
||||||
empty($nonNestables)
|
|
||||||
? []
|
? []
|
||||||
: \array_combine($nonNestables, $nonNestables)
|
: \array_combine($nonNestables, $nonNestables);
|
||||||
);
|
|
||||||
|
|
||||||
// $excerpt is based on the first occurrence of a marker
|
// $excerpt is based on the first occurrence of a marker
|
||||||
|
|
||||||
while ($excerpt = \strpbrk($text, $this->inlineMarkerList)) {
|
while ($exc = \strpbrk($text, $this->inlineMarkerList)) {
|
||||||
$marker = $excerpt[0];
|
$marker = $exc[0];
|
||||||
|
|
||||||
$markerPosition = \strlen($text) - \strlen($excerpt);
|
$markerPosition = \strlen($text) - \strlen($exc);
|
||||||
|
|
||||||
// Get the first char before the marker
|
// Get the first char before the marker
|
||||||
$beforeMarkerPosition = $markerPosition - 1;
|
$beforeMarkerPosition = $markerPosition - 1;
|
||||||
$charBeforeMarker = $beforeMarkerPosition >= 0 ? $text[$markerPosition - 1] : '';
|
$charBeforeMarker = $beforeMarkerPosition >= 0 ? $text[$markerPosition - 1] : '';
|
||||||
|
|
||||||
$Excerpt = ['text' => $excerpt, 'context' => $text, 'before' => $charBeforeMarker];
|
$excerpt = ['text' => $exc, 'context' => $text, 'before' => $charBeforeMarker];
|
||||||
|
|
||||||
foreach ($this->InlineTypes[$marker] as $inlineType) {
|
foreach ($this->InlineTypes[$marker] as $inlineType) {
|
||||||
// check to see if the current inline type is nestable in the current context
|
// check to see if the current inline type is nestable in the current context
|
||||||
|
|
@ -1873,7 +1900,7 @@ class Markdown
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$Inline = $this->{"inline{$inlineType}"}($Excerpt);
|
$Inline = $this->{"inline{$inlineType}"}($excerpt);
|
||||||
|
|
||||||
if (!isset($Inline)) {
|
if (!isset($Inline)) {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -3552,6 +3579,7 @@ class Markdown
|
||||||
'`' => ['Code'],
|
'`' => ['Code'],
|
||||||
'~' => ['Strikethrough'],
|
'~' => ['Strikethrough'],
|
||||||
'\\' => ['EscapeSequence'],
|
'\\' => ['EscapeSequence'],
|
||||||
|
'=' => ['mark'],
|
||||||
];
|
];
|
||||||
|
|
||||||
# ~
|
# ~
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user