mirror of
https://github.com/erusev/parsedown.git
synced 2024-09-20 03:51:29 +02:00
improve extensibility
This commit is contained in:
parent
1aade35c5e
commit
ac68800717
259
Parsedown.php
259
Parsedown.php
@ -372,7 +372,9 @@ class Parsedown
|
|||||||
if (isset($Line['text'][3]) and $Line['text'][3] === '-' and $Line['text'][2] === '-' and $Line['text'][1] === '!')
|
if (isset($Line['text'][3]) and $Line['text'][3] === '-' and $Line['text'][2] === '-' and $Line['text'][1] === '!')
|
||||||
{
|
{
|
||||||
$Block = array(
|
$Block = array(
|
||||||
'element' => $Line['body'],
|
'element' => array(
|
||||||
|
'text' => $Line['body'],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (preg_match('/-->$/', $Line['text']))
|
if (preg_match('/-->$/', $Line['text']))
|
||||||
@ -391,7 +393,7 @@ class Parsedown
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$Block['element'] .= "\n" . $Line['body'];
|
$Block['element']['text'] .= "\n" . $Line['body'];
|
||||||
|
|
||||||
if (preg_match('/-->$/', $Line['text']))
|
if (preg_match('/-->$/', $Line['text']))
|
||||||
{
|
{
|
||||||
@ -643,30 +645,78 @@ class Parsedown
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (preg_match('/^<(\w[\w\d]*)(?:[ ][^>]*)?(\/?)[ ]*>/', $Line['text'], $matches))
|
$attrName = '[a-zA-Z_:][\w:.-]*';
|
||||||
{
|
$attrValue = '(?:[^"\'=<>`\s]+|".*?"|\'.*?\')';
|
||||||
if (in_array($matches[1], $this->textLevelElements))
|
|
||||||
|
preg_match('/^<(\w[\d\w]*)((?:\s'.$attrName.'(?:\s*=\s*'.$attrValue.')?)*)\s*(\/?)>/', $Line['text'], $matches);
|
||||||
|
|
||||||
|
if ( ! $matches or in_array($matches[1], $this->textLevelElements))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$Block = array(
|
$Block = array(
|
||||||
'element' => $Line['body'],
|
'depth' => 0,
|
||||||
|
'element' => array(
|
||||||
|
'name' => $matches[1],
|
||||||
|
'text' => null,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($matches[2] or in_array($matches[1], $this->voidElements) or preg_match('/<\/'.$matches[1].'>[ ]*$/', $Line['text']))
|
$remainder = substr($Line['text'], strlen($matches[0]));
|
||||||
|
|
||||||
|
if (trim($remainder) === '')
|
||||||
|
{
|
||||||
|
if ($matches[3] or in_array($matches[1], $this->voidElements))
|
||||||
{
|
{
|
||||||
$Block['closed'] = true;
|
$Block['closed'] = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$Block['depth'] = 0;
|
if ($matches[3] or in_array($matches[1], $this->voidElements))
|
||||||
$Block['name'] = $matches[1];
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
preg_match('/(.*)<\/'.$matches[1].'>\s*$/i', $remainder, $nestedMatches);
|
||||||
|
|
||||||
|
if ($nestedMatches)
|
||||||
|
{
|
||||||
|
$Block['closed'] = true;
|
||||||
|
$Block['element']['text'] = $nestedMatches[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$Block['element']['text'] = $remainder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! $matches[2])
|
||||||
|
{
|
||||||
|
return $Block;
|
||||||
|
}
|
||||||
|
|
||||||
|
preg_match_all('/\s('.$attrName.')(?:\s*=\s*('.$attrValue.'))?/', $matches[2], $nestedMatches, PREG_SET_ORDER);
|
||||||
|
|
||||||
|
foreach ($nestedMatches as $nestedMatch)
|
||||||
|
{
|
||||||
|
if ( ! isset($nestedMatch[2]))
|
||||||
|
{
|
||||||
|
$Block['element']['attributes'][$nestedMatch[1]] = '';
|
||||||
|
}
|
||||||
|
elseif ($nestedMatch[2][0] === '"' or $nestedMatch[2][0] === '\'')
|
||||||
|
{
|
||||||
|
$Block['element']['attributes'][$nestedMatch[1]] = substr($nestedMatch[2], 1, - 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$Block['element']['attributes'][$nestedMatch[1]] = $nestedMatch[2];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $Block;
|
return $Block;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected function addToMarkup($Line, array $Block)
|
protected function addToMarkup($Line, array $Block)
|
||||||
{
|
{
|
||||||
@ -675,12 +725,12 @@ class Parsedown
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (preg_match('/<'.$Block['name'].'([ ].*[\'"])?[ ]*>/', $Line['text'])) # opening tag
|
if (preg_match('/^<'.$Block['element']['name'].'(?:\s.*[\'"])?\s*>/i', $Line['text'])) # open
|
||||||
{
|
{
|
||||||
$Block['depth'] ++;
|
$Block['depth'] ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stripos($Line['text'], '</'.$Block['name'].'>') !== false) # closing tag
|
if (preg_match('/(.*?)<\/'.$Block['element']['name'].'>\s*$/i', $Line['text'], $matches)) # close
|
||||||
{
|
{
|
||||||
if ($Block['depth'] > 0)
|
if ($Block['depth'] > 0)
|
||||||
{
|
{
|
||||||
@ -688,18 +738,25 @@ class Parsedown
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
$Block['element']['text'] .= "\n";
|
||||||
|
|
||||||
$Block['closed'] = true;
|
$Block['closed'] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$Block['element']['text'] .= $matches[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($Block['interrupted']))
|
if (isset($Block['interrupted']))
|
||||||
{
|
{
|
||||||
$Block['element'] .= "\n";
|
$Block['element']['text'] .= "\n";
|
||||||
|
|
||||||
unset($Block['interrupted']);
|
unset($Block['interrupted']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$Block['element'] .= "\n".$Line['body'];
|
if ( ! isset($Block['closed']))
|
||||||
|
{
|
||||||
|
$Block['element']['text'] .= "\n".$Line['body'];
|
||||||
|
}
|
||||||
|
|
||||||
return $Block;
|
return $Block;
|
||||||
}
|
}
|
||||||
@ -871,6 +928,7 @@ class Parsedown
|
|||||||
'id' => strtolower($matches[1]),
|
'id' => strtolower($matches[1]),
|
||||||
'data' => array(
|
'data' => array(
|
||||||
'url' => $matches[2],
|
'url' => $matches[2],
|
||||||
|
'title' => null,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -906,12 +964,21 @@ class Parsedown
|
|||||||
|
|
||||||
protected function element(array $Element)
|
protected function element(array $Element)
|
||||||
{
|
{
|
||||||
$markup = '<'.$Element['name'];
|
$markup = '';
|
||||||
|
|
||||||
|
if (isset($Element['name']))
|
||||||
|
{
|
||||||
|
$markup .= '<'.$Element['name'];
|
||||||
|
|
||||||
if (isset($Element['attributes']))
|
if (isset($Element['attributes']))
|
||||||
{
|
{
|
||||||
foreach ($Element['attributes'] as $name => $value)
|
foreach ($Element['attributes'] as $name => $value)
|
||||||
{
|
{
|
||||||
|
if ($value === null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$markup .= ' '.$name.'="'.$value.'"';
|
$markup .= ' '.$name.'="'.$value.'"';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -919,7 +986,17 @@ class Parsedown
|
|||||||
if (isset($Element['text']))
|
if (isset($Element['text']))
|
||||||
{
|
{
|
||||||
$markup .= '>';
|
$markup .= '>';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$markup .= ' />';
|
||||||
|
|
||||||
|
return $markup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($Element['text']))
|
||||||
|
{
|
||||||
if (isset($Element['handler']))
|
if (isset($Element['handler']))
|
||||||
{
|
{
|
||||||
$markup .= $this->$Element['handler']($Element['text']);
|
$markup .= $this->$Element['handler']($Element['text']);
|
||||||
@ -928,12 +1005,11 @@ class Parsedown
|
|||||||
{
|
{
|
||||||
$markup .= $Element['text'];
|
$markup .= $Element['text'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$markup .= '</'.$Element['name'].'>';
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (isset($Element['name']))
|
||||||
{
|
{
|
||||||
$markup .= ' />';
|
$markup .= '</'.$Element['name'].'>';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $markup;
|
return $markup;
|
||||||
@ -950,16 +1026,7 @@ class Parsedown
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$markup .= "\n";
|
$markup .= "\n" . $this->element($Element);
|
||||||
|
|
||||||
if (is_string($Element)) # because of Markup
|
|
||||||
{
|
|
||||||
$markup .= $Element;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$markup .= $this->element($Element);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$markup .= "\n";
|
$markup .= "\n";
|
||||||
@ -972,8 +1039,8 @@ class Parsedown
|
|||||||
#
|
#
|
||||||
|
|
||||||
protected $SpanTypes = array(
|
protected $SpanTypes = array(
|
||||||
'!' => array('Link'), # ?
|
|
||||||
'"' => array('QuotationMark'),
|
'"' => array('QuotationMark'),
|
||||||
|
'!' => array('Image'),
|
||||||
'&' => array('Ampersand'),
|
'&' => array('Ampersand'),
|
||||||
'*' => array('Emphasis'),
|
'*' => array('Emphasis'),
|
||||||
'/' => array('Url'),
|
'/' => array('Url'),
|
||||||
@ -1234,92 +1301,98 @@ class Parsedown
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function identifyLink($Excerpt)
|
protected function identifyImage($Excerpt)
|
||||||
{
|
{
|
||||||
$extent = $Excerpt['text'][0] === '!' ? 1 : 0;
|
if ( ! isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '[')
|
||||||
|
|
||||||
if (strpos($Excerpt['text'], ']') and preg_match('/\[((?:[^][]|(?R))*)\]/', $Excerpt['text'], $matches))
|
|
||||||
{
|
|
||||||
$Link = array('text' => $matches[1], 'label' => strtolower($matches[1]));
|
|
||||||
|
|
||||||
$extent += strlen($matches[0]);
|
|
||||||
|
|
||||||
$substring = substr($Excerpt['text'], $extent);
|
|
||||||
|
|
||||||
if (preg_match('/^\s*\[([^][]+)\]/', $substring, $matches))
|
|
||||||
{
|
|
||||||
$Link['label'] = strtolower($matches[1]);
|
|
||||||
|
|
||||||
if (isset($this->Definitions['Reference'][$Link['label']]))
|
|
||||||
{
|
|
||||||
$Link += $this->Definitions['Reference'][$Link['label']];
|
|
||||||
|
|
||||||
$extent += strlen($matches[0]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
elseif (isset($this->Definitions['Reference'][$Link['label']]))
|
|
||||||
{
|
|
||||||
$Link += $this->Definitions['Reference'][$Link['label']];
|
|
||||||
|
|
||||||
if (preg_match('/^[ ]*\[\]/', $substring, $matches))
|
|
||||||
{
|
|
||||||
$extent += strlen($matches[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
elseif (preg_match('/^\([ ]*(.*?)(?:[ ]+[\'"](.+?)[\'"])?[ ]*\)/', $substring, $matches))
|
|
||||||
{
|
|
||||||
$Link['url'] = $matches[1];
|
|
||||||
|
|
||||||
if (isset($matches[2]))
|
|
||||||
{
|
|
||||||
$Link['title'] = $matches[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
$extent += strlen($matches[0]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$url = str_replace(array('&', '<'), array('&', '<'), $Link['url']);
|
$Excerpt['text'] = substr($Excerpt['text'], 1);
|
||||||
|
|
||||||
if ($Excerpt['text'][0] === '!')
|
$Span = $this->identifyLink($Excerpt);
|
||||||
{
|
|
||||||
$Element = array(
|
$Span['extent'] ++;
|
||||||
|
|
||||||
|
$Span['element'] = array(
|
||||||
'name' => 'img',
|
'name' => 'img',
|
||||||
'attributes' => array(
|
'attributes' => array(
|
||||||
'src' => $url,
|
'src' => $Span['element']['attributes']['href'],
|
||||||
'alt' => $Link['text'],
|
'alt' => $Span['element']['text'],
|
||||||
|
'title' => $Span['element']['attributes']['title'],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return $Span;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
protected function identifyLink($Excerpt)
|
||||||
{
|
{
|
||||||
$Element = array(
|
$Element = array(
|
||||||
'name' => 'a',
|
'name' => 'a',
|
||||||
'handler' => 'line',
|
'handler' => 'line',
|
||||||
'text' => $Link['text'],
|
'text' => null,
|
||||||
'attributes' => array(
|
'attributes' => array(
|
||||||
'href' => $url,
|
'href' => null,
|
||||||
|
'title' => null,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$extent = 0;
|
||||||
|
|
||||||
|
$remainder = $Excerpt['text'];
|
||||||
|
|
||||||
|
if (preg_match('/\[((?:[^][]|(?R))*)\]/', $remainder, $matches))
|
||||||
|
{
|
||||||
|
$Element['text'] = $matches[1];
|
||||||
|
|
||||||
|
$extent += strlen($matches[0]);
|
||||||
|
|
||||||
|
$remainder = substr($remainder, $extent);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($Link['title']))
|
if (preg_match('/^\([ ]*([^ ]+)(?:[ ]+(".+?"|\'.+?\'))?[ ]*\)/', $remainder, $matches))
|
||||||
{
|
{
|
||||||
$Element['attributes']['title'] = $Link['title'];
|
$Element['attributes']['href'] = $matches[1];
|
||||||
|
|
||||||
|
if (isset($matches[2]))
|
||||||
|
{
|
||||||
|
$Element['attributes']['title'] = substr($matches[2], 1, - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$extent += strlen($matches[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches))
|
||||||
|
{
|
||||||
|
$definition = $matches[1] ?: $Element['text'];
|
||||||
|
$definition = strtolower($definition);
|
||||||
|
|
||||||
|
$extent += strlen($matches[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$definition = strtolower($Element['text']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! isset($this->Definitions['Reference'][$definition]))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$Definition = $this->Definitions['Reference'][$definition];
|
||||||
|
|
||||||
|
$Element['attributes']['href'] = $Definition['url'];
|
||||||
|
$Element['attributes']['title'] = $Definition['title'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$Element['attributes']['href'] = str_replace(array('&', '<'), array('&', '<'), $Element['attributes']['href']);
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'extent' => $extent,
|
'extent' => $extent,
|
||||||
'element' => $Element,
|
'element' => $Element,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<hr>
|
<hr />
|
||||||
<p>paragraph</p>
|
<p>paragraph</p>
|
||||||
<hr />
|
<hr />
|
||||||
<p>paragraph</p>
|
<p>paragraph</p>
|
||||||
@ -8,5 +8,5 @@
|
|||||||
<p>paragraph</p>
|
<p>paragraph</p>
|
||||||
<hr class="foo" id="bar" />
|
<hr class="foo" id="bar" />
|
||||||
<p>paragraph</p>
|
<p>paragraph</p>
|
||||||
<hr class="foo" id="bar" >
|
<hr class="foo" id="bar" />
|
||||||
<p>paragraph</p>
|
<p>paragraph</p>
|
Loading…
Reference in New Issue
Block a user