1
0
mirror of https://github.com/erusev/parsedown.git synced 2023-08-10 21:13:06 +03:00

improve extensibility

This commit is contained in:
Emanuil Rusev 2014-12-15 01:07:29 +02:00
parent 1aade35c5e
commit ac68800717
2 changed files with 179 additions and 106 deletions

View File

@ -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,29 +645,77 @@ class Parsedown
return; return;
} }
if (preg_match('/^<(\w[\w\d]*)(?:[ ][^>]*)?(\/?)[ ]*>/', $Line['text'], $matches)) $attrName = '[a-zA-Z_:][\w:.-]*';
$attrValue = '(?:[^"\'=<>`\s]+|".*?"|\'.*?\')';
preg_match('/^<(\w[\d\w]*)((?:\s'.$attrName.'(?:\s*=\s*'.$attrValue.')?)*)\s*(\/?)>/', $Line['text'], $matches);
if ( ! $matches or in_array($matches[1], $this->textLevelElements))
{ {
if (in_array($matches[1], $this->textLevelElements)) return;
}
$Block = array(
'depth' => 0,
'element' => array(
'name' => $matches[1],
'text' => null,
),
);
$remainder = substr($Line['text'], strlen($matches[0]));
if (trim($remainder) === '')
{
if ($matches[3] or in_array($matches[1], $this->voidElements))
{
$Block['closed'] = true;
}
}
else
{
if ($matches[3] or in_array($matches[1], $this->voidElements))
{ {
return; return;
} }
$Block = array( preg_match('/(.*)<\/'.$matches[1].'>\s*$/i', $remainder, $nestedMatches);
'element' => $Line['body'],
);
if ($matches[2] or in_array($matches[1], $this->voidElements) or preg_match('/<\/'.$matches[1].'>[ ]*$/', $Line['text'])) if ($nestedMatches)
{ {
$Block['closed'] = true; $Block['closed'] = true;
$Block['element']['text'] = $nestedMatches[1];
} }
else else
{ {
$Block['depth'] = 0; $Block['element']['text'] = $remainder;
$Block['name'] = $matches[1];
} }
}
if ( ! $matches[2])
{
return $Block; 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;
} }
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;
} }
@ -741,7 +798,7 @@ class Parsedown
$alignment = 'left'; $alignment = 'left';
} }
if (substr($dividerCell, -1) === ':') if (substr($dividerCell, - 1) === ':')
{ {
$alignment = $alignment === 'left' ? 'center' : 'right'; $alignment = $alignment === 'left' ? 'center' : 'right';
} }
@ -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,20 +964,39 @@ class Parsedown
protected function element(array $Element) protected function element(array $Element)
{ {
$markup = '<'.$Element['name']; $markup = '';
if (isset($Element['attributes'])) if (isset($Element['name']))
{ {
foreach ($Element['attributes'] as $name => $value) $markup .= '<'.$Element['name'];
if (isset($Element['attributes']))
{ {
$markup .= ' '.$name.'="'.$value.'"'; foreach ($Element['attributes'] as $name => $value)
{
if ($value === null)
{
continue;
}
$markup .= ' '.$name.'="'.$value.'"';
}
}
if (isset($Element['text']))
{
$markup .= '>';
}
else
{
$markup .= ' />';
return $markup;
} }
} }
if (isset($Element['text'])) if (isset($Element['text']))
{ {
$markup .= '>';
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,91 +1301,97 @@ class Parsedown
} }
} }
protected function identifyImage($Excerpt)
{
if ( ! isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '[')
{
return;
}
$Excerpt['text'] = substr($Excerpt['text'], 1);
$Span = $this->identifyLink($Excerpt);
$Span['extent'] ++;
$Span['element'] = array(
'name' => 'img',
'attributes' => array(
'src' => $Span['element']['attributes']['href'],
'alt' => $Span['element']['text'],
'title' => $Span['element']['attributes']['title'],
),
);
return $Span;
}
protected function identifyLink($Excerpt) protected function identifyLink($Excerpt)
{ {
$extent = $Excerpt['text'][0] === '!' ? 1 : 0; $Element = array(
'name' => 'a',
'handler' => 'line',
'text' => null,
'attributes' => array(
'href' => null,
'title' => null,
),
);
if (strpos($Excerpt['text'], ']') and preg_match('/\[((?:[^][]|(?R))*)\]/', $Excerpt['text'], $matches)) $extent = 0;
$remainder = $Excerpt['text'];
if (preg_match('/\[((?:[^][]|(?R))*)\]/', $remainder, $matches))
{ {
$Link = array('text' => $matches[1], 'label' => strtolower($matches[1])); $Element['text'] = $matches[1];
$extent += strlen($matches[0]); $extent += strlen($matches[0]);
$substring = substr($Excerpt['text'], $extent); $remainder = substr($remainder, $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 else
{ {
return; return;
} }
$url = str_replace(array('&', '<'), array('&amp;', '&lt;'), $Link['url']); if (preg_match('/^\([ ]*([^ ]+)(?:[ ]+(".+?"|\'.+?\'))?[ ]*\)/', $remainder, $matches))
if ($Excerpt['text'][0] === '!')
{ {
$Element = array( $Element['attributes']['href'] = $matches[1];
'name' => 'img',
'attributes' => array( if (isset($matches[2]))
'src' => $url, {
'alt' => $Link['text'], $Element['attributes']['title'] = substr($matches[2], 1, - 1);
), }
);
$extent += strlen($matches[0]);
} }
else else
{ {
$Element = array( if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches))
'name' => 'a', {
'handler' => 'line', $definition = $matches[1] ?: $Element['text'];
'text' => $Link['text'], $definition = strtolower($definition);
'attributes' => array(
'href' => $url, $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'];
} }
if (isset($Link['title'])) $Element['attributes']['href'] = str_replace(array('&', '<'), array('&amp;', '&lt;'), $Element['attributes']['href']);
{
$Element['attributes']['title'] = $Link['title'];
}
return array( return array(
'extent' => $extent, 'extent' => $extent,

View File

@ -1,12 +1,12 @@
<hr> <hr />
<p>paragraph</p> <p>paragraph</p>
<hr/> <hr />
<p>paragraph</p> <p>paragraph</p>
<hr /> <hr />
<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>
<hr class="foo" id="bar" > <hr class="foo" id="bar" />
<p>paragraph</p> <p>paragraph</p>