mirror of
https://github.com/erusev/parsedown.git
synced 2023-08-10 21:13:06 +03:00
Compare commits
49 Commits
Author | SHA1 | Date | |
---|---|---|---|
468d1e3da8 | |||
7aa1d97bba | |||
f768f9c63f | |||
aa83968534 | |||
85eadccc05 | |||
c94fa12d67 | |||
11e02d45fa | |||
ecd53f9add | |||
844b2f49ea | |||
65116c3cb0 | |||
147003107a | |||
618b26056c | |||
b828fe7c8d | |||
6c9df528aa | |||
cb8cc57742 | |||
9da19c1108 | |||
ffd9d3b407 | |||
e94ecf4adc | |||
4d3079b908 | |||
70e7a17380 | |||
9518c8e384 | |||
c581284231 | |||
cb1940255a | |||
93d0ec9397 | |||
9c6e7e880a | |||
2d62e29625 | |||
595f33871e | |||
97e1e0efaa | |||
648419467a | |||
6ddb6b2b33 | |||
0008e69a83 | |||
c664785485 | |||
bdf0ef024e | |||
21a3e8790a | |||
e5e8d02934 | |||
7ff0f97811 | |||
596350d1f5 | |||
2cbd3010e4 | |||
3b4aa6bff7 | |||
05a8f16e95 | |||
79d924040a | |||
b4a8eb3315 | |||
4383cce85b | |||
ada39109e4 | |||
a06cdfb814 | |||
6bee326c92 | |||
3fe867d294 | |||
4b7d7cdef2 | |||
97e667ab30 |
@ -5,6 +5,4 @@ php:
|
||||
- 5.5
|
||||
- 5.4
|
||||
- 5.3
|
||||
- 5.2
|
||||
- hhvm
|
||||
|
554
Parsedown.php
554
Parsedown.php
@ -15,15 +15,10 @@
|
||||
|
||||
class Parsedown
|
||||
{
|
||||
#
|
||||
# Philosophy
|
||||
# ~
|
||||
|
||||
# Parsedown recognises that the Markdown syntax is optimised for humans so
|
||||
# it tries to read like one. It goes through text line by line. It looks at
|
||||
# how lines start to identify blocks. It looks for special characters to
|
||||
# identify inline elements.
|
||||
const version = '1.5.1';
|
||||
|
||||
#
|
||||
# ~
|
||||
|
||||
function text($text)
|
||||
@ -53,8 +48,6 @@ class Parsedown
|
||||
# Setters
|
||||
#
|
||||
|
||||
private $breaksEnabled;
|
||||
|
||||
function setBreaksEnabled($breaksEnabled)
|
||||
{
|
||||
$this->breaksEnabled = $breaksEnabled;
|
||||
@ -62,7 +55,7 @@ class Parsedown
|
||||
return $this;
|
||||
}
|
||||
|
||||
private $markupEscaped;
|
||||
protected $breaksEnabled;
|
||||
|
||||
function setMarkupEscaped($markupEscaped)
|
||||
{
|
||||
@ -71,7 +64,7 @@ class Parsedown
|
||||
return $this;
|
||||
}
|
||||
|
||||
private $urlsLinked = true;
|
||||
protected $markupEscaped;
|
||||
|
||||
function setUrlsLinked($urlsLinked)
|
||||
{
|
||||
@ -80,6 +73,8 @@ class Parsedown
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected $urlsLinked = true;
|
||||
|
||||
#
|
||||
# Lines
|
||||
#
|
||||
@ -534,7 +529,7 @@ class Parsedown
|
||||
|
||||
protected function blockListContinue($Line, array $Block)
|
||||
{
|
||||
if ($Block['indent'] === $Line['indent'] and preg_match('/^'.$Block['pattern'].'[ ]+(.*)/', $Line['text'], $matches))
|
||||
if ($Block['indent'] === $Line['indent'] and preg_match('/^'.$Block['pattern'].'(?:[ ]+(.*)|$)/', $Line['text'], $matches))
|
||||
{
|
||||
if (isset($Block['interrupted']))
|
||||
{
|
||||
@ -545,11 +540,13 @@ class Parsedown
|
||||
|
||||
unset($Block['li']);
|
||||
|
||||
$text = isset($matches[1]) ? $matches[1] : '';
|
||||
|
||||
$Block['li'] = array(
|
||||
'name' => 'li',
|
||||
'handler' => 'li',
|
||||
'text' => array(
|
||||
$matches[1],
|
||||
$text,
|
||||
),
|
||||
);
|
||||
|
||||
@ -558,6 +555,11 @@ class Parsedown
|
||||
return $Block;
|
||||
}
|
||||
|
||||
if ($Line['text'][0] === '[' and $this->blockReference($Line))
|
||||
{
|
||||
return $Block;
|
||||
}
|
||||
|
||||
if ( ! isset($Block['interrupted']))
|
||||
{
|
||||
$text = preg_replace('/^[ ]{0,4}/', '', $Line['body']);
|
||||
@ -734,8 +736,6 @@ class Parsedown
|
||||
{
|
||||
$Block['closed'] = true;
|
||||
}
|
||||
|
||||
$Block['markup'] .= $matches[1];
|
||||
}
|
||||
|
||||
if (isset($Block['interrupted']))
|
||||
@ -850,7 +850,7 @@ class Parsedown
|
||||
$alignment = $alignments[$index];
|
||||
|
||||
$HeaderElement['attributes'] = array(
|
||||
'align' => $alignment,
|
||||
'style' => 'text-align: '.$alignment.';',
|
||||
);
|
||||
}
|
||||
|
||||
@ -905,9 +905,9 @@ class Parsedown
|
||||
$row = trim($row);
|
||||
$row = trim($row, '|');
|
||||
|
||||
$cells = explode('|', $row);
|
||||
preg_match_all('/(?:(\\\\[|])|[^|`]|`[^`]+`|`)+/', $row, $matches);
|
||||
|
||||
foreach ($cells as $index => $cell)
|
||||
foreach ($matches[0] as $index => $cell)
|
||||
{
|
||||
$cell = trim($cell);
|
||||
|
||||
@ -920,7 +920,7 @@ class Parsedown
|
||||
if (isset($Block['alignments'][$index]))
|
||||
{
|
||||
$Element['attributes'] = array(
|
||||
'align' => $Block['alignments'][$index],
|
||||
'style' => 'text-align: '.$Block['alignments'][$index].';',
|
||||
);
|
||||
}
|
||||
|
||||
@ -956,75 +956,18 @@ class Parsedown
|
||||
return $Block;
|
||||
}
|
||||
|
||||
#
|
||||
# ~
|
||||
#
|
||||
|
||||
protected function element(array $Element)
|
||||
{
|
||||
$markup = '<'.$Element['name'];
|
||||
|
||||
if (isset($Element['attributes']))
|
||||
{
|
||||
foreach ($Element['attributes'] as $name => $value)
|
||||
{
|
||||
if ($value === null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$markup .= ' '.$name.'="'.$value.'"';
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($Element['text']))
|
||||
{
|
||||
$markup .= '>';
|
||||
|
||||
if (isset($Element['handler']))
|
||||
{
|
||||
$markup .= $this->$Element['handler']($Element['text']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$markup .= $Element['text'];
|
||||
}
|
||||
|
||||
$markup .= '</'.$Element['name'].'>';
|
||||
}
|
||||
else
|
||||
{
|
||||
$markup .= ' />';
|
||||
}
|
||||
|
||||
return $markup;
|
||||
}
|
||||
|
||||
protected function elements(array $Elements)
|
||||
{
|
||||
$markup = '';
|
||||
|
||||
foreach ($Elements as $Element)
|
||||
{
|
||||
$markup .= "\n" . $this->element($Element);
|
||||
}
|
||||
|
||||
$markup .= "\n";
|
||||
|
||||
return $markup;
|
||||
}
|
||||
|
||||
#
|
||||
# Inline Elements
|
||||
#
|
||||
|
||||
protected $InlineTypes = array(
|
||||
'"' => array('QuotationMark'),
|
||||
'"' => array('SpecialCharacter'),
|
||||
'!' => array('Image'),
|
||||
'&' => array('Ampersand'),
|
||||
'&' => array('SpecialCharacter'),
|
||||
'*' => array('Emphasis'),
|
||||
'<' => array('UrlTag', 'EmailTag', 'Tag', 'LessThan'),
|
||||
'>' => array('GreaterThan'),
|
||||
':' => array('Url'),
|
||||
'<' => array('UrlTag', 'EmailTag', 'Markup', 'SpecialCharacter'),
|
||||
'>' => array('SpecialCharacter'),
|
||||
'[' => array('Link'),
|
||||
'_' => array('Emphasis'),
|
||||
'`' => array('Code'),
|
||||
@ -1034,7 +977,7 @@ class Parsedown
|
||||
|
||||
# ~
|
||||
|
||||
protected $inlineMarkerList = '!"*_&[<>`~\\';
|
||||
protected $inlineMarkerList = '!"*_&[:<>`~\\';
|
||||
|
||||
#
|
||||
# ~
|
||||
@ -1044,43 +987,53 @@ class Parsedown
|
||||
{
|
||||
$markup = '';
|
||||
|
||||
$remainder = $text;
|
||||
$unexaminedText = $text;
|
||||
|
||||
$markerPosition = 0;
|
||||
|
||||
while ($excerpt = strpbrk($remainder, $this->inlineMarkerList))
|
||||
while ($excerpt = strpbrk($unexaminedText, $this->inlineMarkerList))
|
||||
{
|
||||
$marker = $excerpt[0];
|
||||
|
||||
$markerPosition += strpos($remainder, $marker);
|
||||
$markerPosition += strpos($unexaminedText, $marker);
|
||||
|
||||
$Excerpt = array('text' => $excerpt, 'context' => $text);
|
||||
|
||||
foreach ($this->InlineTypes[$marker] as $inlineType)
|
||||
{
|
||||
$handler = 'inline'.$inlineType;
|
||||
|
||||
$Inline = $this->$handler($excerpt);
|
||||
$Inline = $this->{'inline'.$inlineType}($Excerpt);
|
||||
|
||||
if ( ! isset($Inline))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$plainText = substr($text, 0, $markerPosition);
|
||||
if (isset($Inline['position']) and $Inline['position'] > $markerPosition) # position is ahead of marker
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$markup .= $this->unmarkedText($plainText);
|
||||
if ( ! isset($Inline['position']))
|
||||
{
|
||||
$Inline['position'] = $markerPosition;
|
||||
}
|
||||
|
||||
$unmarkedText = substr($text, 0, $Inline['position']);
|
||||
|
||||
$markup .= $this->unmarkedText($unmarkedText);
|
||||
|
||||
$markup .= isset($Inline['markup']) ? $Inline['markup'] : $this->element($Inline['element']);
|
||||
|
||||
$text = substr($text, $markerPosition + $Inline['extent']);
|
||||
$text = substr($text, $Inline['position'] + $Inline['extent']);
|
||||
|
||||
$remainder = $text;
|
||||
$unexaminedText = $text;
|
||||
|
||||
$markerPosition = 0;
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
$remainder = substr($excerpt, 1);
|
||||
$unexaminedText = substr($excerpt, 1);
|
||||
|
||||
$markerPosition ++;
|
||||
}
|
||||
@ -1094,94 +1047,29 @@ class Parsedown
|
||||
# ~
|
||||
#
|
||||
|
||||
protected function inlineAmpersand($excerpt)
|
||||
protected function inlineCode($Excerpt)
|
||||
{
|
||||
if ( ! preg_match('/^&#?\w+;/', $excerpt))
|
||||
{
|
||||
return array(
|
||||
'markup' => '&',
|
||||
'extent' => 1,
|
||||
);
|
||||
}
|
||||
}
|
||||
$marker = $Excerpt['text'][0];
|
||||
|
||||
protected function inlineStrikethrough($excerpt)
|
||||
{
|
||||
if ( ! isset($excerpt[1]))
|
||||
if (preg_match('/^('.$marker.'+)[ ]*(.+?)[ ]*(?<!'.$marker.')\1(?!'.$marker.')/s', $Excerpt['text'], $matches))
|
||||
{
|
||||
return;
|
||||
}
|
||||
$text = $matches[2];
|
||||
$text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
|
||||
$text = preg_replace("/[ ]*\n/", ' ', $text);
|
||||
|
||||
if ($excerpt[1] === '~' and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $excerpt, $matches))
|
||||
{
|
||||
return array(
|
||||
'extent' => strlen($matches[0]),
|
||||
'element' => array(
|
||||
'name' => 'del',
|
||||
'text' => $matches[1],
|
||||
'handler' => 'line',
|
||||
'name' => 'code',
|
||||
'text' => $text,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function inlineEscapeSequence($excerpt)
|
||||
protected function inlineEmailTag($Excerpt)
|
||||
{
|
||||
if (isset($excerpt[1]) and in_array($excerpt[1], $this->specialCharacters))
|
||||
{
|
||||
return array(
|
||||
'markup' => $excerpt[1],
|
||||
'extent' => 2,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function inlineLessThan()
|
||||
{
|
||||
return array(
|
||||
'markup' => '<',
|
||||
'extent' => 1,
|
||||
);
|
||||
}
|
||||
|
||||
protected function inlineGreaterThan()
|
||||
{
|
||||
return array(
|
||||
'markup' => '>',
|
||||
'extent' => 1,
|
||||
);
|
||||
}
|
||||
|
||||
protected function inlineQuotationMark()
|
||||
{
|
||||
return array(
|
||||
'markup' => '"',
|
||||
'extent' => 1,
|
||||
);
|
||||
}
|
||||
|
||||
protected function inlineUrlTag($excerpt)
|
||||
{
|
||||
if (strpos($excerpt, '>') !== false and preg_match('/^<(https?:[\/]{2}[^\s]+?)>/i', $excerpt, $matches))
|
||||
{
|
||||
$url = str_replace(array('&', '<'), array('&', '<'), $matches[1]);
|
||||
|
||||
return array(
|
||||
'extent' => strlen($matches[0]),
|
||||
'element' => array(
|
||||
'name' => 'a',
|
||||
'text' => $url,
|
||||
'attributes' => array(
|
||||
'href' => $url,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function inlineEmailTag($excerpt)
|
||||
{
|
||||
if (strpos($excerpt, '>') !== false and preg_match('/^<((mailto:)?\S+?@\S+?)>/i', $excerpt, $matches))
|
||||
if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<((mailto:)?\S+?@\S+?)>/i', $Excerpt['text'], $matches))
|
||||
{
|
||||
$url = $matches[1];
|
||||
|
||||
@ -1203,77 +1091,84 @@ class Parsedown
|
||||
}
|
||||
}
|
||||
|
||||
protected function inlineTag($excerpt)
|
||||
protected function inlineEmphasis($Excerpt)
|
||||
{
|
||||
if ($this->markupEscaped)
|
||||
if ( ! isset($Excerpt['text'][1]))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (strpos($excerpt, '>') !== false and preg_match('/^<\/?\w.*?>/s', $excerpt, $matches))
|
||||
$marker = $Excerpt['text'][0];
|
||||
|
||||
if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches))
|
||||
{
|
||||
return array(
|
||||
'markup' => $matches[0],
|
||||
'extent' => strlen($matches[0]),
|
||||
);
|
||||
$emphasis = 'strong';
|
||||
}
|
||||
}
|
||||
|
||||
protected function inlineCode($excerpt)
|
||||
{
|
||||
$marker = $excerpt[0];
|
||||
|
||||
if (preg_match('/^('.$marker.'+)[ ]*(.+?)[ ]*(?<!'.$marker.')\1(?!'.$marker.')/s', $excerpt, $matches))
|
||||
elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches))
|
||||
{
|
||||
$text = $matches[2];
|
||||
$text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
|
||||
$text = preg_replace("/[ ]*\n/", ' ', $text);
|
||||
|
||||
return array(
|
||||
'extent' => strlen($matches[0]),
|
||||
'element' => array(
|
||||
'name' => 'code',
|
||||
'text' => $text,
|
||||
),
|
||||
);
|
||||
$emphasis = 'em';
|
||||
}
|
||||
}
|
||||
|
||||
protected function inlineImage($excerpt)
|
||||
{
|
||||
if ( ! isset($excerpt[1]) or $excerpt[1] !== '[')
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$excerpt = substr($excerpt, 1);
|
||||
return array(
|
||||
'extent' => strlen($matches[0]),
|
||||
'element' => array(
|
||||
'name' => $emphasis,
|
||||
'handler' => 'line',
|
||||
'text' => $matches[1],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
$InlineLink = $this->inlineLink($excerpt);
|
||||
protected function inlineEscapeSequence($Excerpt)
|
||||
{
|
||||
if (isset($Excerpt['text'][1]) and in_array($Excerpt['text'][1], $this->specialCharacters))
|
||||
{
|
||||
return array(
|
||||
'markup' => $Excerpt['text'][1],
|
||||
'extent' => 2,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($InlineLink === null)
|
||||
protected function inlineImage($Excerpt)
|
||||
{
|
||||
if ( ! isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '[')
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$Excerpt['text']= substr($Excerpt['text'], 1);
|
||||
|
||||
$Link = $this->inlineLink($Excerpt);
|
||||
|
||||
if ($Link === null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$Inline = array(
|
||||
'extent' => $InlineLink['extent'] + 1,
|
||||
'extent' => $Link['extent'] + 1,
|
||||
'element' => array(
|
||||
'name' => 'img',
|
||||
'attributes' => array(
|
||||
'src' => $InlineLink['element']['attributes']['href'],
|
||||
'alt' => $InlineLink['element']['text'],
|
||||
'src' => $Link['element']['attributes']['href'],
|
||||
'alt' => $Link['element']['text'],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$Inline['element']['attributes'] += $InlineLink['element']['attributes'];
|
||||
$Inline['element']['attributes'] += $Link['element']['attributes'];
|
||||
|
||||
unset($Inline['element']['attributes']['href']);
|
||||
|
||||
return $Inline;
|
||||
}
|
||||
|
||||
protected function inlineLink($excerpt)
|
||||
protected function inlineLink($Excerpt)
|
||||
{
|
||||
$Element = array(
|
||||
'name' => 'a',
|
||||
@ -1287,7 +1182,7 @@ class Parsedown
|
||||
|
||||
$extent = 0;
|
||||
|
||||
$remainder = $excerpt;
|
||||
$remainder = $Excerpt['text'];
|
||||
|
||||
if (preg_match('/\[((?:[^][]|(?R))*)\]/', $remainder, $matches))
|
||||
{
|
||||
@ -1302,7 +1197,7 @@ class Parsedown
|
||||
return;
|
||||
}
|
||||
|
||||
if (preg_match('/^[(]((?:[^ (]|[(][^ )]+[)])+)(?:[ ]+("[^"]+"|\'[^\']+\'))?[)]/', $remainder, $matches))
|
||||
if (preg_match('/^[(]((?:[^ ()]|[(][^ )]+[)])+)(?:[ ]+("[^"]*"|\'[^\']*\'))?[)]/', $remainder, $matches))
|
||||
{
|
||||
$Element['attributes']['href'] = $matches[1];
|
||||
|
||||
@ -1346,59 +1241,126 @@ class Parsedown
|
||||
);
|
||||
}
|
||||
|
||||
protected function inlineEmphasis($excerpt)
|
||||
protected function inlineMarkup($Excerpt)
|
||||
{
|
||||
if ( ! isset($excerpt[1]))
|
||||
if ($this->markupEscaped or strpos($Excerpt['text'], '>') === false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$marker = $excerpt[0];
|
||||
|
||||
if ($excerpt[1] === $marker and preg_match($this->StrongRegex[$marker], $excerpt, $matches))
|
||||
if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w*[ ]*>/s', $Excerpt['text'], $matches))
|
||||
{
|
||||
$emphasis = 'strong';
|
||||
}
|
||||
elseif (preg_match($this->EmRegex[$marker], $excerpt, $matches))
|
||||
{
|
||||
$emphasis = 'em';
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
return array(
|
||||
'markup' => $matches[0],
|
||||
'extent' => strlen($matches[0]),
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'extent' => strlen($matches[0]),
|
||||
'element' => array(
|
||||
'name' => $emphasis,
|
||||
'handler' => 'line',
|
||||
'text' => $matches[1],
|
||||
),
|
||||
);
|
||||
if ($Excerpt['text'][1] === '!' and preg_match('/^<!---?[^>-](?:-?[^-])*-->/s', $Excerpt['text'], $matches))
|
||||
{
|
||||
return array(
|
||||
'markup' => $matches[0],
|
||||
'extent' => strlen($matches[0]),
|
||||
);
|
||||
}
|
||||
|
||||
if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w*(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*\/?>/s', $Excerpt['text'], $matches))
|
||||
{
|
||||
return array(
|
||||
'markup' => $matches[0],
|
||||
'extent' => strlen($matches[0]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# ~
|
||||
protected function inlineSpecialCharacter($Excerpt)
|
||||
{
|
||||
if ($Excerpt['text'][0] === '&' and ! preg_match('/^&#?\w+;/', $Excerpt['text']))
|
||||
{
|
||||
return array(
|
||||
'markup' => '&',
|
||||
'extent' => 1,
|
||||
);
|
||||
}
|
||||
|
||||
protected $unmarkedInlineTypes = array("\n" => 'Break', '://' => 'Url');
|
||||
$SpecialCharacter = array('>' => 'gt', '<' => 'lt', '"' => 'quot');
|
||||
|
||||
if (isset($SpecialCharacter[$Excerpt['text'][0]]))
|
||||
{
|
||||
return array(
|
||||
'markup' => '&'.$SpecialCharacter[$Excerpt['text'][0]].';',
|
||||
'extent' => 1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function inlineStrikethrough($Excerpt)
|
||||
{
|
||||
if ( ! isset($Excerpt['text'][1]))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $Excerpt['text'], $matches))
|
||||
{
|
||||
return array(
|
||||
'extent' => strlen($matches[0]),
|
||||
'element' => array(
|
||||
'name' => 'del',
|
||||
'text' => $matches[1],
|
||||
'handler' => 'line',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function inlineUrl($Excerpt)
|
||||
{
|
||||
if ($this->urlsLinked !== true or ! isset($Excerpt['text'][2]) or $Excerpt['text'][2] !== '/')
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (preg_match('/\bhttps?:[\/]{2}[^\s<]+\b\/*/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE))
|
||||
{
|
||||
$Inline = array(
|
||||
'extent' => strlen($matches[0][0]),
|
||||
'position' => $matches[0][1],
|
||||
'element' => array(
|
||||
'name' => 'a',
|
||||
'text' => $matches[0][0],
|
||||
'attributes' => array(
|
||||
'href' => $matches[0][0],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return $Inline;
|
||||
}
|
||||
}
|
||||
|
||||
protected function inlineUrlTag($Excerpt)
|
||||
{
|
||||
if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w+:\/{2}[^ >]+)>/i', $Excerpt['text'], $matches))
|
||||
{
|
||||
$url = str_replace(array('&', '<'), array('&', '<'), $matches[1]);
|
||||
|
||||
return array(
|
||||
'extent' => strlen($matches[0]),
|
||||
'element' => array(
|
||||
'name' => 'a',
|
||||
'text' => $url,
|
||||
'attributes' => array(
|
||||
'href' => $url,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
# ~
|
||||
|
||||
protected function unmarkedText($text)
|
||||
{
|
||||
foreach ($this->unmarkedInlineTypes as $snippet => $inlineType)
|
||||
{
|
||||
if (strpos($text, $snippet) !== false)
|
||||
{
|
||||
$text = $this->{'unmarkedInline'.$inlineType}($text);
|
||||
}
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
protected function unmarkedInlineBreak($text)
|
||||
{
|
||||
if ($this->breaksEnabled)
|
||||
{
|
||||
@ -1413,38 +1375,65 @@ class Parsedown
|
||||
return $text;
|
||||
}
|
||||
|
||||
protected function unmarkedInlineUrl($text)
|
||||
#
|
||||
# Handlers
|
||||
#
|
||||
|
||||
protected function element(array $Element)
|
||||
{
|
||||
if ($this->urlsLinked !== true)
|
||||
$markup = '<'.$Element['name'];
|
||||
|
||||
if (isset($Element['attributes']))
|
||||
{
|
||||
return $text;
|
||||
foreach ($Element['attributes'] as $name => $value)
|
||||
{
|
||||
if ($value === null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$markup .= ' '.$name.'="'.$value.'"';
|
||||
}
|
||||
}
|
||||
|
||||
$re = '/\bhttps?:[\/]{2}[^\s<]+\b\/*/ui';
|
||||
|
||||
$offset = 0;
|
||||
|
||||
while (strpos($text, '://', $offset) and preg_match($re, $text, $matches, PREG_OFFSET_CAPTURE, $offset))
|
||||
if (isset($Element['text']))
|
||||
{
|
||||
$url = $matches[0][0];
|
||||
$markup .= '>';
|
||||
|
||||
$urlLength = strlen($url);
|
||||
$urlPosition = $matches[0][1];
|
||||
if (isset($Element['handler']))
|
||||
{
|
||||
$markup .= $this->{$Element['handler']}($Element['text']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$markup .= $Element['text'];
|
||||
}
|
||||
|
||||
$markup = '<a href="'.$url.'">'.$url.'</a>';
|
||||
$markupLength = strlen($markup);
|
||||
|
||||
$text = substr_replace($text, $markup, $urlPosition, $urlLength);
|
||||
|
||||
$offset = $urlPosition + $markupLength;
|
||||
$markup .= '</'.$Element['name'].'>';
|
||||
}
|
||||
else
|
||||
{
|
||||
$markup .= ' />';
|
||||
}
|
||||
|
||||
return $text;
|
||||
return $markup;
|
||||
}
|
||||
|
||||
protected function elements(array $Elements)
|
||||
{
|
||||
$markup = '';
|
||||
|
||||
foreach ($Elements as $Element)
|
||||
{
|
||||
$markup .= "\n" . $this->element($Element);
|
||||
}
|
||||
|
||||
$markup .= "\n";
|
||||
|
||||
return $markup;
|
||||
}
|
||||
|
||||
#
|
||||
# ~
|
||||
#
|
||||
|
||||
protected function li($lines)
|
||||
{
|
||||
@ -1466,7 +1455,18 @@ class Parsedown
|
||||
}
|
||||
|
||||
#
|
||||
# Multiton
|
||||
# Deprecated Methods
|
||||
#
|
||||
|
||||
function parse($text)
|
||||
{
|
||||
$markup = $this->text($text);
|
||||
|
||||
return $markup;
|
||||
}
|
||||
|
||||
#
|
||||
# Static Methods
|
||||
#
|
||||
|
||||
static function instance($name = 'default')
|
||||
@ -1485,22 +1485,6 @@ class Parsedown
|
||||
|
||||
private static $instances = array();
|
||||
|
||||
#
|
||||
# Deprecated Methods
|
||||
#
|
||||
|
||||
/**
|
||||
* @deprecated in favor of "text"
|
||||
* @param $text
|
||||
* @return string
|
||||
*/
|
||||
function parse($text)
|
||||
{
|
||||
$markup = $this->text($text);
|
||||
|
||||
return $markup;
|
||||
}
|
||||
|
||||
#
|
||||
# Fields
|
||||
#
|
||||
@ -1508,10 +1492,10 @@ class Parsedown
|
||||
protected $DefinitionData;
|
||||
|
||||
#
|
||||
# Read-only
|
||||
# Read-Only
|
||||
|
||||
protected $specialCharacters = array(
|
||||
'\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!',
|
||||
'\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!', '|',
|
||||
);
|
||||
|
||||
protected $StrongRegex = array(
|
||||
|
18
README.md
18
README.md
@ -1,18 +1,20 @@
|
||||
## Parsedown
|
||||
|
||||
[](https://travis-ci.org/erusev/parsedown)
|
||||
<!--[](https://packagist.org/packages/erusev/parsedown)-->
|
||||
|
||||
Better Markdown Parser in PHP
|
||||
|
||||
[[ demo ]](http://parsedown.org/demo)
|
||||
[See Demo](http://parsedown.org/demo)
|
||||
|
||||
### Features
|
||||
|
||||
* [Fast](http://parsedown.org/speed)
|
||||
* [Consistent](http://parsedown.org/consistency)
|
||||
* [GitHub flavored](https://help.github.com/articles/github-flavored-markdown)
|
||||
* [Tested](http://parsedown.org/tests/) in PHP 5.2, 5.3, 5.4, 5.5, 5.6 and [hhvm](http://www.hhvm.com/)
|
||||
* Extensible
|
||||
* [Tested](http://parsedown.org/tests/) in PHP 5.3, 5.4, 5.5, 5.6 and [HHVM](http://www.hhvm.com/)
|
||||
* [Extensible](https://github.com/erusev/parsedown/wiki/Writing-Extensions)
|
||||
* [Markdown Extra extension](https://github.com/erusev/parsedown-extra)
|
||||
* [JavaScript port](https://github.com/hkdobrev/parsedown.js) under development
|
||||
|
||||
### Installation
|
||||
|
||||
@ -36,14 +38,14 @@ It tries to read Markdown like a human. First, it looks at the lines. It’s int
|
||||
|
||||
We call this approach "line based". We believe that Parsedown is the first Markdown parser to use it. Since the release of Parsedown, other developers have used the same approach to develop other Markdown parsers in PHP and in other languages.
|
||||
|
||||
**Is Parsedown compliant with CommonMark?**
|
||||
**Is it compliant with CommonMark?**
|
||||
|
||||
The majority of the CommonMark tests pass. Most of the tests that don't pass deal with cases that are quite extreme. Yet, we are working on them. As CommonMark matures, compliance should improve.
|
||||
It passes most of the CommonMark tests. Most of the tests that don't pass deal with cases that are quite uncommon. Still, as CommonMark matures, compliance should improve.
|
||||
|
||||
**Who uses Parsedown?**
|
||||
**Who uses it?**
|
||||
|
||||
[phpDocumentor](http://www.phpdoc.org/), [October CMS](http://octobercms.com/), [Bolt CMS](http://bolt.cm/), [Kirby CMS](http://getkirby.com/), [Grav CMS](http://getgrav.org/), [Statamic CMS](http://www.statamic.com/), [RaspberryPi.org](http://www.raspberrypi.org/) and [more](https://www.versioneye.com/php/erusev:parsedown/references).
|
||||
|
||||
**How can I help?**
|
||||
|
||||
Use the project, tell friends about it and if you feel generous, [donate some money](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=528P3NZQMP8N2).
|
||||
Use it, star it, share it and if you feel generous, [donate some money](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=528P3NZQMP8N2).
|
||||
|
@ -1,21 +1,21 @@
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th align="left">header 1</th>
|
||||
<th align="center">header 2</th>
|
||||
<th align="right">header 2</th>
|
||||
<th style="text-align: left;">header 1</th>
|
||||
<th style="text-align: center;">header 2</th>
|
||||
<th style="text-align: right;">header 2</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left">cell 1.1</td>
|
||||
<td align="center">cell 1.2</td>
|
||||
<td align="right">cell 1.3</td>
|
||||
<td style="text-align: left;">cell 1.1</td>
|
||||
<td style="text-align: center;">cell 1.2</td>
|
||||
<td style="text-align: right;">cell 1.3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">cell 2.1</td>
|
||||
<td align="center">cell 2.2</td>
|
||||
<td align="right">cell 2.3</td>
|
||||
<td style="text-align: left;">cell 2.1</td>
|
||||
<td style="text-align: center;">cell 2.2</td>
|
||||
<td style="text-align: right;">cell 2.3</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
@ -1,13 +1,12 @@
|
||||
<div>_content_</div>
|
||||
<p>sparse:</p>
|
||||
<div>
|
||||
<div class="inner">
|
||||
_content_
|
||||
</div>
|
||||
</div>
|
||||
<p>paragraph</p>
|
||||
<div>
|
||||
<div class="inner">
|
||||
_content_
|
||||
</div>
|
||||
</div>
|
||||
<style type="text/css">
|
||||
p {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
p {color: #789;}
|
||||
</style>
|
||||
<div>
|
||||
<a href="/">home</a></div>
|
@ -1,17 +1,16 @@
|
||||
<div>_content_</div>
|
||||
|
||||
sparse:
|
||||
|
||||
<div>
|
||||
<div class="inner">
|
||||
_content_
|
||||
</div>
|
||||
</div>
|
||||
|
||||
paragraph
|
||||
|
||||
<div>
|
||||
<div class="inner">
|
||||
_content_
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style type="text/css">
|
||||
p {
|
||||
color: red;
|
||||
}
|
||||
p {color: #789;}
|
||||
</style>
|
||||
|
||||
<div>
|
||||
<a href="/">home</a></div>
|
@ -1 +1,2 @@
|
||||
<p><img src="/md.png" alt="alt" title="title" /></p>
|
||||
<p><img src="/md.png" alt="alt" title="title" /></p>
|
||||
<p><img src="/md.png" alt="blank title" title="" /></p>
|
@ -1 +1,3 @@
|
||||

|
||||

|
||||
|
||||

|
@ -1,4 +1,6 @@
|
||||
<p><a href="http://example.com">link</a> and <a href="/url-with-(parentheses)">another link</a></p>
|
||||
<p><a href="http://example.com">link</a></p>
|
||||
<p><a href="/url-(parentheses)">link</a> with parentheses in URL </p>
|
||||
<p>(<a href="/index.php">link</a>) in parentheses</p>
|
||||
<p><a href="http://example.com"><code>link</code></a></p>
|
||||
<p><a href="http://example.com"><img src="http://parsedown.org/md.png" alt="MD Logo" /></a></p>
|
||||
<p><a href="http://example.com"><img src="http://parsedown.org/md.png" alt="MD Logo" /> and text</a></p>
|
@ -1,4 +1,8 @@
|
||||
[link](http://example.com) and [another link](/url-with-(parentheses))
|
||||
[link](http://example.com)
|
||||
|
||||
[link](/url-(parentheses)) with parentheses in URL
|
||||
|
||||
([link](/index.php)) in parentheses
|
||||
|
||||
[`link`](http://example.com)
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
<p><a href="http://example.com" title="Title">single quotes</a></p>
|
||||
<p><a href="http://example.com" title="Title">double quotes</a></p>
|
||||
<p><a href="http://example.com" title="">single quotes blank</a></p>
|
||||
<p><a href="http://example.com" title="">double quotes blank</a></p>
|
||||
<p><a href="http://example.com" title="2 Words">space</a></p>
|
||||
<p><a href="http://example.com/url-(parentheses)" title="Title">parentheses</a></p>
|
@ -2,6 +2,10 @@
|
||||
|
||||
[double quotes](http://example.com "Title")
|
||||
|
||||
[single quotes blank](http://example.com '')
|
||||
|
||||
[double quotes blank](http://example.com "")
|
||||
|
||||
[space](http://example.com "2 Words")
|
||||
|
||||
[parentheses](http://example.com/url-(parentheses) "Title")
|
@ -20,17 +20,17 @@
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th align="left">header 1</th>
|
||||
<th style="text-align: left;">header 1</th>
|
||||
<th>header 2</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left">cell 1.1</td>
|
||||
<td style="text-align: left;">cell 1.1</td>
|
||||
<td>cell 1.2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">cell 2.1</td>
|
||||
<td style="text-align: left;">cell 2.1</td>
|
||||
<td>cell 2.2</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
@ -11,8 +11,12 @@
|
||||
<td><del>cell</del> 1.2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>cell</code> 2.1</td>
|
||||
<td>cell 2.2</td>
|
||||
<td><code>|</code> 2.1</td>
|
||||
<td>| 2.2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>\|</code> 2.1</td>
|
||||
<td><a href="/">link</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
@ -1,4 +1,5 @@
|
||||
| _header_ 1 | header 2 |
|
||||
| ------------ | ------------ |
|
||||
| _cell_ 1.1 | ~~cell~~ 1.2 |
|
||||
| `cell` 2.1 | cell 2.2 |
|
||||
| `|` 2.1 | \| 2.2 |
|
||||
| `\|` 2.1 | [link](/) |
|
Reference in New Issue
Block a user