first commit
This commit is contained in:
		
							
								
								
									
										20
									
								
								vendor/erusev/parsedown-extra/LICENSE.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								vendor/erusev/parsedown-extra/LICENSE.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| The MIT License (MIT) | ||||
|  | ||||
| Copyright (c) 2013 Emanuil Rusev, erusev.com | ||||
|  | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||
| this software and associated documentation files (the "Software"), to deal in | ||||
| the Software without restriction, including without limitation the rights to | ||||
| use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||||
| the Software, and to permit persons to whom the Software is furnished to do so, | ||||
| subject to the following conditions: | ||||
|  | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
|  | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||||
| FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||||
| COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||||
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||||
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
							
								
								
									
										526
									
								
								vendor/erusev/parsedown-extra/ParsedownExtra.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										526
									
								
								vendor/erusev/parsedown-extra/ParsedownExtra.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,526 @@ | ||||
| <?php | ||||
|  | ||||
| # | ||||
| # | ||||
| # Parsedown Extra | ||||
| # https://github.com/erusev/parsedown-extra | ||||
| # | ||||
| # (c) Emanuil Rusev | ||||
| # http://erusev.com | ||||
| # | ||||
| # For the full license information, view the LICENSE file that was distributed | ||||
| # with this source code. | ||||
| # | ||||
| # | ||||
|  | ||||
| class ParsedownExtra extends Parsedown | ||||
| { | ||||
|     # ~ | ||||
|  | ||||
|     const version = '0.7.0'; | ||||
|  | ||||
|     # ~ | ||||
|  | ||||
|     function __construct() | ||||
|     { | ||||
|         if (parent::version < '1.5.0') | ||||
|         { | ||||
|             throw new Exception('ParsedownExtra requires a later version of Parsedown'); | ||||
|         } | ||||
|  | ||||
|         $this->BlockTypes[':'] []= 'DefinitionList'; | ||||
|         $this->BlockTypes['*'] []= 'Abbreviation'; | ||||
|  | ||||
|         # identify footnote definitions before reference definitions | ||||
|         array_unshift($this->BlockTypes['['], 'Footnote'); | ||||
|  | ||||
|         # identify footnote markers before before links | ||||
|         array_unshift($this->InlineTypes['['], 'FootnoteMarker'); | ||||
|     } | ||||
|  | ||||
|     # | ||||
|     # ~ | ||||
|  | ||||
|     function text($text) | ||||
|     { | ||||
|         $markup = parent::text($text); | ||||
|  | ||||
|         # merge consecutive dl elements | ||||
|  | ||||
|         $markup = preg_replace('/<\/dl>\s+<dl>\s+/', '', $markup); | ||||
|  | ||||
|         # add footnotes | ||||
|  | ||||
|         if (isset($this->DefinitionData['Footnote'])) | ||||
|         { | ||||
|             $Element = $this->buildFootnoteElement(); | ||||
|  | ||||
|             $markup .= "\n" . $this->element($Element); | ||||
|         } | ||||
|  | ||||
|         return $markup; | ||||
|     } | ||||
|  | ||||
|     # | ||||
|     # Blocks | ||||
|     # | ||||
|  | ||||
|     # | ||||
|     # Abbreviation | ||||
|  | ||||
|     protected function blockAbbreviation($Line) | ||||
|     { | ||||
|         if (preg_match('/^\*\[(.+?)\]:[ ]*(.+?)[ ]*$/', $Line['text'], $matches)) | ||||
|         { | ||||
|             $this->DefinitionData['Abbreviation'][$matches[1]] = $matches[2]; | ||||
|  | ||||
|             $Block = array( | ||||
|                 'hidden' => true, | ||||
|             ); | ||||
|  | ||||
|             return $Block; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     # | ||||
|     # Footnote | ||||
|  | ||||
|     protected function blockFootnote($Line) | ||||
|     { | ||||
|         if (preg_match('/^\[\^(.+?)\]:[ ]?(.*)$/', $Line['text'], $matches)) | ||||
|         { | ||||
|             $Block = array( | ||||
|                 'label' => $matches[1], | ||||
|                 'text' => $matches[2], | ||||
|                 'hidden' => true, | ||||
|             ); | ||||
|  | ||||
|             return $Block; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     protected function blockFootnoteContinue($Line, $Block) | ||||
|     { | ||||
|         if ($Line['text'][0] === '[' and preg_match('/^\[\^(.+?)\]:/', $Line['text'])) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if (isset($Block['interrupted'])) | ||||
|         { | ||||
|             if ($Line['indent'] >= 4) | ||||
|             { | ||||
|                 $Block['text'] .= "\n\n" . $Line['text']; | ||||
|  | ||||
|                 return $Block; | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             $Block['text'] .= "\n" . $Line['text']; | ||||
|  | ||||
|             return $Block; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     protected function blockFootnoteComplete($Block) | ||||
|     { | ||||
|         $this->DefinitionData['Footnote'][$Block['label']] = array( | ||||
|             'text' => $Block['text'], | ||||
|             'count' => null, | ||||
|             'number' => null, | ||||
|         ); | ||||
|  | ||||
|         return $Block; | ||||
|     } | ||||
|  | ||||
|     # | ||||
|     # Definition List | ||||
|  | ||||
|     protected function blockDefinitionList($Line, $Block) | ||||
|     { | ||||
|         if ( ! isset($Block) or isset($Block['type'])) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         $Element = array( | ||||
|             'name' => 'dl', | ||||
|             'handler' => 'elements', | ||||
|             'text' => array(), | ||||
|         ); | ||||
|  | ||||
|         $terms = explode("\n", $Block['element']['text']); | ||||
|  | ||||
|         foreach ($terms as $term) | ||||
|         { | ||||
|             $Element['text'] []= array( | ||||
|                 'name' => 'dt', | ||||
|                 'handler' => 'line', | ||||
|                 'text' => $term, | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         $Block['element'] = $Element; | ||||
|  | ||||
|         $Block = $this->addDdElement($Line, $Block); | ||||
|  | ||||
|         return $Block; | ||||
|     } | ||||
|  | ||||
|     protected function blockDefinitionListContinue($Line, array $Block) | ||||
|     { | ||||
|         if ($Line['text'][0] === ':') | ||||
|         { | ||||
|             $Block = $this->addDdElement($Line, $Block); | ||||
|  | ||||
|             return $Block; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             if (isset($Block['interrupted']) and $Line['indent'] === 0) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             if (isset($Block['interrupted'])) | ||||
|             { | ||||
|                 $Block['dd']['handler'] = 'text'; | ||||
|                 $Block['dd']['text'] .= "\n\n"; | ||||
|  | ||||
|                 unset($Block['interrupted']); | ||||
|             } | ||||
|  | ||||
|             $text = substr($Line['body'], min($Line['indent'], 4)); | ||||
|  | ||||
|             $Block['dd']['text'] .= "\n" . $text; | ||||
|  | ||||
|             return $Block; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     # | ||||
|     # Header | ||||
|  | ||||
|     protected function blockHeader($Line) | ||||
|     { | ||||
|         $Block = parent::blockHeader($Line); | ||||
|  | ||||
|         if (preg_match('/[ #]*{('.$this->regexAttribute.'+)}[ ]*$/', $Block['element']['text'], $matches, PREG_OFFSET_CAPTURE)) | ||||
|         { | ||||
|             $attributeString = $matches[1][0]; | ||||
|  | ||||
|             $Block['element']['attributes'] = $this->parseAttributeData($attributeString); | ||||
|  | ||||
|             $Block['element']['text'] = substr($Block['element']['text'], 0, $matches[0][1]); | ||||
|         } | ||||
|  | ||||
|         return $Block; | ||||
|     } | ||||
|  | ||||
|     # | ||||
|     # Markup | ||||
|  | ||||
|     protected function blockMarkupComplete($Block) | ||||
|     { | ||||
|         if ( ! isset($Block['void'])) | ||||
|         { | ||||
|             $Block['markup'] = $this->processTag($Block['markup']); | ||||
|         } | ||||
|  | ||||
|         return $Block; | ||||
|     } | ||||
|  | ||||
|     # | ||||
|     # Setext | ||||
|  | ||||
|     protected function blockSetextHeader($Line, array $Block = null) | ||||
|     { | ||||
|         $Block = parent::blockSetextHeader($Line, $Block); | ||||
|  | ||||
|         if (preg_match('/[ ]*{('.$this->regexAttribute.'+)}[ ]*$/', $Block['element']['text'], $matches, PREG_OFFSET_CAPTURE)) | ||||
|         { | ||||
|             $attributeString = $matches[1][0]; | ||||
|  | ||||
|             $Block['element']['attributes'] = $this->parseAttributeData($attributeString); | ||||
|  | ||||
|             $Block['element']['text'] = substr($Block['element']['text'], 0, $matches[0][1]); | ||||
|         } | ||||
|  | ||||
|         return $Block; | ||||
|     } | ||||
|  | ||||
|     # | ||||
|     # Inline Elements | ||||
|     # | ||||
|  | ||||
|     # | ||||
|     # Footnote Marker | ||||
|  | ||||
|     protected function inlineFootnoteMarker($Excerpt) | ||||
|     { | ||||
|         if (preg_match('/^\[\^(.+?)\]/', $Excerpt['text'], $matches)) | ||||
|         { | ||||
|             $name = $matches[1]; | ||||
|  | ||||
|             if ( ! isset($this->DefinitionData['Footnote'][$name])) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             $this->DefinitionData['Footnote'][$name]['count'] ++; | ||||
|  | ||||
|             if ( ! isset($this->DefinitionData['Footnote'][$name]['number'])) | ||||
|             { | ||||
|                 $this->DefinitionData['Footnote'][$name]['number'] = ++ $this->footnoteCount; # » & | ||||
|             } | ||||
|  | ||||
|             $Element = array( | ||||
|                 'name' => 'sup', | ||||
|                 'attributes' => array('id' => 'fnref'.$this->DefinitionData['Footnote'][$name]['count'].':'.$name), | ||||
|                 'handler' => 'element', | ||||
|                 'text' => array( | ||||
|                     'name' => 'a', | ||||
|                     'attributes' => array('href' => '#fn:'.$name, 'class' => 'footnote-ref'), | ||||
|                     'text' => $this->DefinitionData['Footnote'][$name]['number'], | ||||
|                 ), | ||||
|             ); | ||||
|  | ||||
|             return array( | ||||
|                 'extent' => strlen($matches[0]), | ||||
|                 'element' => $Element, | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private $footnoteCount = 0; | ||||
|  | ||||
|     # | ||||
|     # Link | ||||
|  | ||||
|     protected function inlineLink($Excerpt) | ||||
|     { | ||||
|         $Link = parent::inlineLink($Excerpt); | ||||
|  | ||||
|         $remainder = substr($Excerpt['text'], $Link['extent']); | ||||
|  | ||||
|         if (preg_match('/^[ ]*{('.$this->regexAttribute.'+)}/', $remainder, $matches)) | ||||
|         { | ||||
|             $Link['element']['attributes'] += $this->parseAttributeData($matches[1]); | ||||
|  | ||||
|             $Link['extent'] += strlen($matches[0]); | ||||
|         } | ||||
|  | ||||
|         return $Link; | ||||
|     } | ||||
|  | ||||
|     # | ||||
|     # ~ | ||||
|     # | ||||
|  | ||||
|     protected function unmarkedText($text) | ||||
|     { | ||||
|         $text = parent::unmarkedText($text); | ||||
|  | ||||
|         if (isset($this->DefinitionData['Abbreviation'])) | ||||
|         { | ||||
|             foreach ($this->DefinitionData['Abbreviation'] as $abbreviation => $meaning) | ||||
|             { | ||||
|                 $pattern = '/\b'.preg_quote($abbreviation, '/').'\b/'; | ||||
|  | ||||
|                 $text = preg_replace($pattern, '<abbr title="'.$meaning.'">'.$abbreviation.'</abbr>', $text); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $text; | ||||
|     } | ||||
|  | ||||
|     # | ||||
|     # Util Methods | ||||
|     # | ||||
|  | ||||
|     protected function addDdElement(array $Line, array $Block) | ||||
|     { | ||||
|         $text = substr($Line['text'], 1); | ||||
|         $text = trim($text); | ||||
|  | ||||
|         unset($Block['dd']); | ||||
|  | ||||
|         $Block['dd'] = array( | ||||
|             'name' => 'dd', | ||||
|             'handler' => 'line', | ||||
|             'text' => $text, | ||||
|         ); | ||||
|  | ||||
|         if (isset($Block['interrupted'])) | ||||
|         { | ||||
|             $Block['dd']['handler'] = 'text'; | ||||
|  | ||||
|             unset($Block['interrupted']); | ||||
|         } | ||||
|  | ||||
|         $Block['element']['text'] []= & $Block['dd']; | ||||
|  | ||||
|         return $Block; | ||||
|     } | ||||
|  | ||||
|     protected function buildFootnoteElement() | ||||
|     { | ||||
|         $Element = array( | ||||
|             'name' => 'div', | ||||
|             'attributes' => array('class' => 'footnotes'), | ||||
|             'handler' => 'elements', | ||||
|             'text' => array( | ||||
|                 array( | ||||
|                     'name' => 'hr', | ||||
|                 ), | ||||
|                 array( | ||||
|                     'name' => 'ol', | ||||
|                     'handler' => 'elements', | ||||
|                     'text' => array(), | ||||
|                 ), | ||||
|             ), | ||||
|         ); | ||||
|  | ||||
|         uasort($this->DefinitionData['Footnote'], 'self::sortFootnotes'); | ||||
|  | ||||
|         foreach ($this->DefinitionData['Footnote'] as $definitionId => $DefinitionData) | ||||
|         { | ||||
|             if ( ! isset($DefinitionData['number'])) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             $text = $DefinitionData['text']; | ||||
|  | ||||
|             $text = parent::text($text); | ||||
|  | ||||
|             $numbers = range(1, $DefinitionData['count']); | ||||
|  | ||||
|             $backLinksMarkup = ''; | ||||
|  | ||||
|             foreach ($numbers as $number) | ||||
|             { | ||||
|                 $backLinksMarkup .= ' <a href="#fnref'.$number.':'.$definitionId.'" rev="footnote" class="footnote-backref">↩</a>'; | ||||
|             } | ||||
|  | ||||
|             $backLinksMarkup = substr($backLinksMarkup, 1); | ||||
|  | ||||
|             if (substr($text, - 4) === '</p>') | ||||
|             { | ||||
|                 $backLinksMarkup = ' '.$backLinksMarkup; | ||||
|  | ||||
|                 $text = substr_replace($text, $backLinksMarkup.'</p>', - 4); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 $text .= "\n".'<p>'.$backLinksMarkup.'</p>'; | ||||
|             } | ||||
|  | ||||
|             $Element['text'][1]['text'] []= array( | ||||
|                 'name' => 'li', | ||||
|                 'attributes' => array('id' => 'fn:'.$definitionId), | ||||
|                 'text' => "\n".$text."\n", | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         return $Element; | ||||
|     } | ||||
|  | ||||
|     # ~ | ||||
|  | ||||
|     protected function parseAttributeData($attributeString) | ||||
|     { | ||||
|         $Data = array(); | ||||
|  | ||||
|         $attributes = preg_split('/[ ]+/', $attributeString, - 1, PREG_SPLIT_NO_EMPTY); | ||||
|  | ||||
|         foreach ($attributes as $attribute) | ||||
|         { | ||||
|             if ($attribute[0] === '#') | ||||
|             { | ||||
|                 $Data['id'] = substr($attribute, 1); | ||||
|             } | ||||
|             else # "." | ||||
|             { | ||||
|                 $classes []= substr($attribute, 1); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (isset($classes)) | ||||
|         { | ||||
|             $Data['class'] = implode(' ', $classes); | ||||
|         } | ||||
|  | ||||
|         return $Data; | ||||
|     } | ||||
|  | ||||
|     # ~ | ||||
|  | ||||
|     protected function processTag($elementMarkup) # recursive | ||||
|     { | ||||
|         # http://stackoverflow.com/q/1148928/200145 | ||||
|         libxml_use_internal_errors(true); | ||||
|  | ||||
|         $DOMDocument = new DOMDocument; | ||||
|  | ||||
|         # http://stackoverflow.com/q/11309194/200145 | ||||
|         $elementMarkup = mb_convert_encoding($elementMarkup, 'HTML-ENTITIES', 'UTF-8'); | ||||
|  | ||||
|         # http://stackoverflow.com/q/4879946/200145 | ||||
|         $DOMDocument->loadHTML($elementMarkup); | ||||
|         $DOMDocument->removeChild($DOMDocument->doctype); | ||||
|         $DOMDocument->replaceChild($DOMDocument->firstChild->firstChild->firstChild, $DOMDocument->firstChild); | ||||
|  | ||||
|         $elementText = ''; | ||||
|  | ||||
|         if ($DOMDocument->documentElement->getAttribute('markdown') === '1') | ||||
|         { | ||||
|             foreach ($DOMDocument->documentElement->childNodes as $Node) | ||||
|             { | ||||
|                 $elementText .= $DOMDocument->saveHTML($Node); | ||||
|             } | ||||
|  | ||||
|             $DOMDocument->documentElement->removeAttribute('markdown'); | ||||
|  | ||||
|             $elementText = "\n".$this->text($elementText)."\n"; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             foreach ($DOMDocument->documentElement->childNodes as $Node) | ||||
|             { | ||||
|                 $nodeMarkup = $DOMDocument->saveHTML($Node); | ||||
|  | ||||
|                 if ($Node instanceof DOMElement and ! in_array($Node->nodeName, $this->textLevelElements)) | ||||
|                 { | ||||
|                     $elementText .= $this->processTag($nodeMarkup); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     $elementText .= $nodeMarkup; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         # because we don't want for markup to get encoded | ||||
|         $DOMDocument->documentElement->nodeValue = 'placeholder\x1A'; | ||||
|  | ||||
|         $markup = $DOMDocument->saveHTML($DOMDocument->documentElement); | ||||
|         $markup = str_replace('placeholder\x1A', $elementText, $markup); | ||||
|  | ||||
|         return $markup; | ||||
|     } | ||||
|  | ||||
|     # ~ | ||||
|  | ||||
|     protected function sortFootnotes($A, $B) # callback | ||||
|     { | ||||
|         return $A['number'] - $B['number']; | ||||
|     } | ||||
|  | ||||
|     # | ||||
|     # Fields | ||||
|     # | ||||
|  | ||||
|     protected $regexAttribute = '(?:[#.][-\w]+[ ]*)'; | ||||
| } | ||||
							
								
								
									
										31
									
								
								vendor/erusev/parsedown-extra/README.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								vendor/erusev/parsedown-extra/README.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| > You might also like [Caret](http://caret.io?ref=parsedown) - our Markdown editor for the Desktop. | ||||
|  | ||||
| ## Parsedown Extra | ||||
|  | ||||
| [](https://travis-ci.org/erusev/parsedown-extra) | ||||
|  | ||||
| An extension of [Parsedown](http://parsedown.org) that adds support for [Markdown Extra](https://michelf.ca/projects/php-markdown/extra/). | ||||
|  | ||||
| [See Demo](http://parsedown.org/extra/) | ||||
|  | ||||
| ### Installation | ||||
|  | ||||
| Include both `Parsedown.php` and `ParsedownExtra.php` or install [the composer package](https://packagist.org/packages/erusev/parsedown-extra). | ||||
|  | ||||
| ### Example | ||||
|  | ||||
| ``` php | ||||
| $Extra = new ParsedownExtra(); | ||||
|  | ||||
| echo $Extra->text('# Header {.sth}'); # prints: <h1 class="sth">Header</h1> | ||||
| ``` | ||||
|  | ||||
| ### Questions | ||||
|  | ||||
| **Who uses Parsedown Extra?** | ||||
|  | ||||
| [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/) and [more](https://www.versioneye.com/php/erusev:parsedown-extra/references). | ||||
|  | ||||
| **How can I help?** | ||||
|  | ||||
| Use it, star it, share it and in case you feel generous, [donate some money](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=528P3NZQMP8N2). | ||||
		Reference in New Issue
	
	Block a user