diff --git a/PHP Markdown Extra Readme.text b/PHP Markdown Extra Readme.text new file mode 100644 index 0000000..f2ad3b3 --- /dev/null +++ b/PHP Markdown Extra Readme.text @@ -0,0 +1,325 @@ +PHP Markdown Extra +================== + +Version 1.0.1oo - Fri 19 May 2006 + +by Michel Fortin + + +based on Markdown by John Gruber + + + +Introduction +------------ + +This is a special version of PHP Markdown with extra features. See + for details. + +Markdown is a text-to-HTML conversion tool for web writers. Markdown +allows you to write using an easy-to-read, easy-to-write plain text +format, then convert it to structurally valid XHTML (or HTML). + +"Markdown" is two things: a plain text markup syntax, and a software +tool, written in Perl, that converts the plain text markup to HTML. +PHP Markdown is a port to PHP of the original Markdown program by +John Gruber. + +PHP Markdown can work as a plug-in for WordPress and bBlog, as a +modifier for the Smarty templating engine, or as a remplacement for +textile formatting in any software that support textile. + +Full documentation of Markdown's syntax is available on John's +Markdown page: + + +Installation and Requirement +---------------------------- + +PHP Markdown requires PHP version 4.0.5 or later. + + +### WordPress ### + +PHP Markdown works with [WordPress][wp], version 1.2 or later. +PHP Markdown is already bundled with WordPress. Still, you can find +here the latest version that may be newer than the latest WordPress +version. + + [wp]: http://wordpress.org/ + +1. To use PHP Markdown with WordPress, place the "makrdown.php" file + in the "plugins" folder. This folder is located inside + "wp-content" at the root of your site: + + (site home)/wp-content/plugins/ + +2. Activate the plugin with the administrative interface of + WordPress. In the "Plugins" section you will now find Markdown. + To activate the plugin, click on the "Activate" button on the + same line than Markdown. Your entries will now be formatted by + PHP Markdown. + +You can configure PHP Markdown to not apply to the comments on your +WordPress weblog. See the "Configuration" section below. + +Note: It is not possible at this time to apply a different set of +filters to different entries. All your entries will be formated by +PHP Markdown. This is currently a limitation of WordPress. If your old +entries are written in HTML (as opposed to another formatting syntax), +your site should not suffer much from installing PHP Markdown. + + +### bBlog ### + +PHP Markdown also works with the latest version of [bBlog][bb]. + + [bb]: http://www.bblog.com/ + +1. To use PHP Markdown with bBlog, rename "markdown.php" to + "modifier.markdown.php" and place the file in the "bBlog_plugins" + folder. This folder is located inside the "bblog" directory of + your site, like this: + + (site home)/bblog/bBlog_plugins/modifier.markdown.php + +2. Select "Markdown" as the "Entry Modifier" when you post a new + entry. This setting will only apply to the entry you are editing. + + +### Replacing Textile ### + +Many web programs written in PHP use [Textile][tx] to format your text. +To use PHP Markdown with these programs without having to change the +code, you can use PHP Markdown in "Textile Compatibility Mode." + + [tx]: http://www.textism.com/tools/textile/ + +1. Rename the "markdown.php" file to "classTextile.php". + +2. Locate the "classTextile.php" file hidden somewhere inside the + installation of your program (see table below). Replace it with + the PHP Markdown file you just renamed. + +As an helper, here you can learn where is the "classTextile.php" file +in some web programs: + + Program Location + ---------------------------------------------------------------- + TextPattern (site home)/textpattern/lib/classTextile.php + Pivot (site home)/pivot/includes/textile/classtextile.php + +Contrary to Textile, Markdown does not convert quotes to curly ones +and does not convert multiple hyphens (`--` and `---`) into en- and +em-dashes. If you use PHP Markdown in Textile Compatibility Mode, you +can solve this problem by installing the "smartypants.php" file from +[PHP SmartyPants][psp] beside the "classTextile.php" file. The Textile +Compatibility Mode function will use SmartyPants automatically without +further modification. + + [psp]: http://www.michelf.com/projects/php-smartypants/ + + +### In Your Own Programs ### + +You can use PHP Markdown easily in your current PHP program. Simply +include the file and then call the Markdown function on the text you +want to convert: + + include_once "markdown.php"; + $my_html = Markdown($my_text); + +If you wish to use PHP Markdown with another text filter function +built to parse HTML, you should filter the text *after* the Markdown +function call. This is an example with [PHP SmartyPants][psp]: + + $my_html = SmartyPants(Markdown($my_text)); + + +### With Smarty ### + +If your program use the [Smarty][sm] template engine, PHP Markdown +can now be used as a modifier for your templates. Rename "markdown.php" +to "modifier.markdown.php" and put it in your smarty plugins folder. + + [sm]: http://smarty.php.net/ + +If you are using MovableType 3.1 or later, the Smarty plugin folder is +located at `(MT CGI root)/php/extlib/smarty/plugins`. This will allow +Markdown to work on dynamic pages. + + +Configuration +------------- + +By default, PHP Markdown produces XHTML output for tags with empty +elements. E.g.: + +
+ +Markdown can be configured to produce HTML-style tags; e.g.: + +
+ +To do this, you must edit the "$md_empty_element_suffix" variable +below the "Global default settings" header at the start of the +"markdown.php" file. + + +### WordPress-Specific Settings ### + +By default, the Markdown plugin applies to both posts and comments on +your WordPress weblog. To deactivate one or the other, edit the +`$md_wp_posts` or `$md_wp_comments` variable under the "WordPress +settings" header at the start of the "markdown.php" file. + + +Bugs +---- + +To file bug reports please send email to: + + +Please include with your report: (1) the example input; (2) the output you +expected; (3) the output PHP Markdown actually produced. + + +Version History +--------------- + +1.0.1oo (19 May 2006) + +* Converted PHP Markdown and PHP Markdown Extra to a object-oriented design. + + +1.0.1 (9 December 2005) + +* Fixed a problem occurring with PHP 5.1.1 due to a small + change to strings variable replacement behaviour in + this version. + + +1.0 (5 September 2005) + +* Added support for setting the id attributes for headers like this: + + Header 1 {#header1} + ======== + + ## Header 2 ## {#header2} + + This only work only for headers for now. + +* Tables will now work correctly as the first element of a definition + list. For example, this input: + + Term + + : Header | Header + ------- | ------- + Cell | Cell + + used to produce no definition list and a table where the first + header was named ": Header". This is now fixed. + +* Fix for a problem where a paragraph following a table was not + placed between `

` tags. + + +1.0b4 (1 August 2005) + +* Fixed some issues where whitespace around HTML blocks were trigging + empty paragraph tags. + +* Fixed an HTML block parsing issue that would cause a block element + following a code span or block with unmatched opening bracket to be + placed inside a paragraph. + +* Removed some PHP notices that could appear when parsing definition + lists and tables with PHP notice reporting flag set. + + +1.0b3 (29 July 2005) + +* Definition lists now require a blank line before each term. Solves + an ambiguity where the last line of lazy-indented definitions could + be mistaken by PHP Markdown as a new term in the list. + +* Definition lists now support multiple terms per definition. + +* Some special tags were replaced in the output by their md5 hash + key. Things such as this now work as expected: + + ## Header ## + + +1.0b2 (26 July 2005) + +* Definition lists can now take two or more definitions for one term. + This should have been the case before, but a bug prevented this + from working right. + +* Fixed a problem where single column table with a pipe only at the + end where not parsed as table. Here is such a table: + + | header + | ------ + | cell + +* Fixed problems with empty cells in the first column of a table with + no leading pipe, like this one: + + header | header + ------ | ------ + | cell + +* Code spans containing pipes did not within a table. This is now + fixed by parsing code spans before splitting rows into cells. + +* Added the pipe character to the backlash escape character lists. + + +1.0b1 (25 Jun 2005) + +* First public release of PHP Markdown Extra. + + +Copyright and License +--------------------- + +Copyright (c) 2004-2006 Michel Fortin + +All rights reserved. + +Based on Markdown +Copyright (c) 2003-2005 John Gruber + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the + distribution. + +* Neither the name "Markdown" nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +This software is provided by the copyright holders and contributors "as +is" and any express or implied warranties, including, but not limited +to, the implied warranties of merchantability and fitness for a +particular purpose are disclaimed. In no event shall the copyright owner +or contributors be liable for any direct, indirect, incidental, special, +exemplary, or consequential damages (including, but not limited to, +procurement of substitute goods or services; loss of use, data, or +profits; or business interruption) however caused and on any theory of +liability, whether in contract, strict liability, or tort (including +negligence or otherwise) arising in any way out of the use of this +software, even if advised of the possibility of such damage. diff --git a/PHP Markdown Readme.text b/PHP Markdown Readme.text deleted file mode 100644 index 101dff1..0000000 --- a/PHP Markdown Readme.text +++ /dev/null @@ -1,478 +0,0 @@ -PHP Markdown -============ - -Version 1.0.1oo - Fri 19 May 2006 - -by Michel Fortin - - -based on work by John Gruber - - - -Introduction ------------- - -Markdown is a text-to-HTML conversion tool for web writers. Markdown -allows you to write using an easy-to-read, easy-to-write plain text -format, then convert it to structurally valid XHTML (or HTML). - -"Markdown" is two things: a plain text markup syntax, and a software -tool, written in Perl, that converts the plain text markup to HTML. -PHP Markdown is a port to PHP of the original Markdown program by -John Gruber. - -PHP Markdown can work as a plug-in for WordPress and bBlog, as a -modifier for the Smarty templating engine, or as a remplacement for -textile formatting in any software that support textile. - -Full documentation of Markdown's syntax is available on John's -Markdown page: - - -Installation and Requirement ----------------------------- - -PHP Markdown requires PHP version 4.0.5 or later. - - -### WordPress ### - -PHP Markdown works with [WordPress][wp], version 1.2 or later. -PHP Markdown is already bundled with WordPress. Still, you can find -here the latest version that may be newer than the latest WordPress -version. - - [wp]: http://wordpress.org/ - -1. To use PHP Markdown with WordPress, place the "makrdown.php" file - in the "plugins" folder. This folder is located inside - "wp-content" at the root of your site: - - (site home)/wp-content/plugins/ - -2. Activate the plugin with the administrative interface of - WordPress. In the "Plugins" section you will now find Markdown. - To activate the plugin, click on the "Activate" button on the - same line than Markdown. Your entries will now be formatted by - PHP Markdown. - -You can configure PHP Markdown to not apply to the comments on your -WordPress weblog. See the "Configuration" section below. - -Note: It is not possible at this time to apply a different set of -filters to different entries. All your entries will be formated by -PHP Markdown. This is currently a limitation of WordPress. If your old -entries are written in HTML (as opposed to another formatting syntax), -your site should not suffer much from installing PHP Markdown. - - -### bBlog ### - -PHP Markdown also works with the latest version of [bBlog][bb]. - - [bb]: http://www.bblog.com/ - -1. To use PHP Markdown with bBlog, rename "markdown.php" to - "modifier.markdown.php" and place the file in the "bBlog_plugins" - folder. This folder is located inside the "bblog" directory of - your site, like this: - - (site home)/bblog/bBlog_plugins/modifier.markdown.php - -2. Select "Markdown" as the "Entry Modifier" when you post a new - entry. This setting will only apply to the entry you are editing. - - -### Replacing Textile ### - -Many web programs written in PHP use [Textile][tx] to format your text. -To use PHP Markdown with these programs without having to change the -code, you can use PHP Markdown in "Textile Compatibility Mode." - - [tx]: http://www.textism.com/tools/textile/ - -1. Rename the "markdown.php" file to "classTextile.php". - -2. Locate the "classTextile.php" file hidden somewhere inside the - installation of your program (see table below). Replace it with - the PHP Markdown file you just renamed. - -As an helper, here you can learn where is the "classTextile.php" file -in some web programs: - - Program Location - ---------------------------------------------------------------- - TextPattern (site home)/textpattern/lib/classTextile.php - Pivot (site home)/pivot/includes/textile/classtextile.php - -Contrary to Textile, Markdown does not convert quotes to curly ones -and does not convert multiple hyphens (`--` and `---`) into en- and -em-dashes. If you use PHP Markdown in Textile Compatibility Mode, you -can solve this problem by installing the "smartypants.php" file from -[PHP SmartyPants][psp] beside the "classTextile.php" file. The Textile -Compatibility Mode function will use SmartyPants automatically without -further modification. - - [psp]: http://www.michelf.com/projects/php-smartypants/ - - -### In Your Own Programs ### - -You can use PHP Markdown easily in your current PHP program. Simply -include the file and then call the Markdown function on the text you -want to convert: - - include_once "markdown.php"; - $my_html = Markdown($my_text); - -If you wish to use PHP Markdown with another text filter function -built to parse HTML, you should filter the text *after* the Markdown -function call. This is an example with [PHP SmartyPants][psp]: - - $my_html = SmartyPants(Markdown($my_text)); - - -### With Smarty ### - -If your program use the [Smarty][sm] template engine, PHP Markdown -can now be used as a modifier for your templates. Rename "markdown.php" -to "modifier.markdown.php" and put it in your smarty plugins folder. - - [sm]: http://smarty.php.net/ - -If you are using MovableType 3.1 or later, the Smarty plugin folder is -located at `(MT CGI root)/php/extlib/smarty/plugins`. This will allow -Markdown to work on dynamic pages. - - -Configuration -------------- - -By default, PHP Markdown produces XHTML output for tags with empty -elements. E.g.: - -
- -Markdown can be configured to produce HTML-style tags; e.g.: - -
- -To do this, you must edit the "$md_empty_element_suffix" variable -below the "Global default settings" header at the start of the -"markdown.php" file. - - -### WordPress-Specific Settings ### - -By default, the Markdown plugin applies to both posts and comments on -your WordPress weblog. To deactivate one or the other, edit the -`$md_wp_posts` or `$md_wp_comments` variable under the "WordPress -settings" header at the start of the "markdown.php" file. - - -Bugs ----- - -To file bug reports please send email to: - - -Please include with your report: (1) the example input; (2) the output you -expected; (3) the output PHP Markdown actually produced. - - -Version History ---------------- - -1.0.1oo (19 May 2006) - -* Converted PHP Markdown to a object-oriented design. - - -1.0.1c (9 Dec 2005) - -* Fixed a problem occurring with PHP 5.1.1 due to a small - change to strings variable replacement behaviour in - this version. - - -1.0.1b (6 Jun 2005) - -* Fixed a bug where an inline image followed by a reference link would - give a completely wrong result. - -* Fix for escaped backticks still triggering code spans: - - There are two raw backticks here: \` and here: \`, not a code span - -* Fix for an ordered list following an unordered list, and the - reverse. There is now a loop in _DoList that does the two - separately. - -* Fix for nested sub-lists in list-paragraph mode. Previously we got - a spurious extra level of `

` tags for something like this: - - * this - - * sub - - that - -* Fixed some incorrect behaviour with emphasis. This will now work - as it should: - - *test **thing*** - **test *thing*** - ***thing* test** - ***thing** test* - - Name: __________ - Address: _______ - -* Correct a small bug in `_TokenizeHTML` where a Doctype declaration - was not seen as HTML. - -* Major rewrite of the WordPress integration code that should - correct many problems by preventing default WordPress filters from - tampering with Markdown-formatted text. More details here: - - -* Added a configuration variable for WordPress that can disable the - Markdown filter on comments. - - -1.0.1a (15 Apr 2005) - -* Fixed an issue where PHP warnings were trigged when converting - text with list items running on PHP 4.0.6. This was comming from - the `rtrim` function which did not support the second argument - prior version 4.1. Replaced by a regular expression. - -* Markdown now filter correctly post excerpts and comment - excerpts in WordPress. - -* Automatic links and some code sample were "corrected" by - the balenceTag filter in WordPress meant to ensure HTML - is well formed. This new version of PHP Markdown postpone this - filter so that it runs after Markdown. - -* Blockquote syntax and some code sample were stripped by - a new WordPress 1.5 filter meant to remove unwanted HTML - in comments. This new version of PHP Markdown postpone this - filter so that it runs after Markdown. - - -1.0.2b1 (5 Mar 2005) - -* Fix for backticks within HTML tag: - - like this - -* Fix for escaped backticks still triggering code spans: - - There are two raw backticks here: \` and here: \`, not a code span - -* Improved integration with WordPress. With WordPress 1.5, the - balenceTags filter now runs after Markdown, so it won't - interfere anymore. You can still disable balanceTags from the admin - interface (in Options > Writing) if you want to. - -* PHP Markdown now correctly filter text for excerpts in WordPress. - There is still one glitch: autolinks and tags in code samples are - stripped by WordPress when trimming it. A fix for this is possible - with WordPress 1.5, but would require duplicating WordPress entry - trimming code within Markdown, which I can't do because of a license - issue. (Nor do I think it is a good solution to fix this.) - -* Improved Textile compatibility mode. Markdown will now honor the - no-image and the lite parameters. In lite mode, no header, blockquote, - list, or code block will be made, and inline HTML is limited - to the following tags: - - - - This is acheived by backslash-escaping block markers before sending - text through the Markdown filter. - - The improved Textile comatibility means that the Markdown syntax will now - be processed for comments in TextPattern (only for span elements due to - TextPattern using the lite mode for comments). Sadly, due to TextPattern - tag stripping, sample code in code span and auto-links will be stripped - before the Markdown filter can see them. So I guess I should say it - half-work for comments TextPattern. - - -1.0.1 (16 Dec 2004): - -* Changed the syntax rules for code blocks and spans. Previously, - backslash escapes for special Markdown characters were processed - everywhere other than within inline HTML tags. Now, the contents of - code blocks and spans are no longer processed for backslash escapes. - This means that code blocks and spans are now treated literally, - with no special rules to worry about regarding backslashes. - - **IMPORTANT**: This breaks the syntax from all previous versions of - Markdown. Code blocks and spans involving backslash characters will - now generate different output than before. - - Implementation-wise, this change was made by moving the call to - `_EscapeSpecialChars()` from the top-level `Markdown()` function to - within `_RunSpanGamut()`. - -* Significants performance improvement in `_DoHeader`, `_Detab` - and `_TokenizeHTML`. - -* Added `>`, `+`, and `-` to the list of backslash-escapable - characters. These should have been done when these characters - were added as unordered list item markers. - -* Inline links using `<` and `>` URL delimiters weren't working: - - like [this]() - - Fixed by moving `_DoAutoLinks()` after `_DoAnchors()` in - `_RunSpanGamut()`. - -* Fixed bug where auto-links were being processed within code spans: - - like this: `` - - Fixed by moving `_DoAutoLinks()` from `_RunBlockGamut()` to - `_RunSpanGamut()`. - -* Sort-of fixed a bug where lines in the middle of hard-wrapped - paragraphs, which lines look like the start of a list item, - would accidentally trigger the creation of a list. E.g. a - paragraph that looked like this: - - I recommend upgrading to version - 8. Oops, now this line is treated - as a sub-list. - - This is fixed for top-level lists, but it can still happen for - sub-lists. E.g., the following list item will not be parsed - properly: - - * I recommend upgrading to version - 8. Oops, now this line is treated - as a sub-list. - - Given Markdown's list-creation rules, I'm not sure this can - be fixed. - -* Fix for horizontal rules preceded by 2 or 3 spaces or followed by - trailing spaces and tabs. - -* Standalone HTML comments are now handled; previously, they'd get - wrapped in a spurious `

` tag. - -* `_HashHTMLBlocks()` now tolerates trailing spaces and tabs following - HTML comments and `


` tags. - -* Changed special case pattern for hashing `
` tags in - `_HashHTMLBlocks()` so that they must occur within three spaces - of left margin. (With 4 spaces or a tab, they should be - code blocks, but weren't before this fix.) - -* Auto-linked email address can now optionally contain - a 'mailto:' protocol. I.e. these are equivalent: - - - - -* Fixed annoying bug where nested lists would wind up with - spurious (and invalid) `

` tags. - -* Changed `_StripLinkDefinitions()` so that link definitions must - occur within three spaces of the left margin. Thus if you indent - a link definition by four spaces or a tab, it will now be a code - block. - -* You can now write empty links: - - [like this]() - - and they'll be turned into anchor tags with empty href attributes. - This should have worked before, but didn't. - -* `***this***` and `___this___` are now turned into - - this - - Instead of - - this - - which isn't valid. - -* Fixed problem for links defined with urls that include parens, e.g.: - - [1]: http://sources.wikipedia.org/wiki/Middle_East_Policy_(Chomsky) - - "Chomsky" was being erroneously treated as the URL's title. - -* Double quotes in the title of an inline link used to give strange - results (incorrectly made entities). Fixed. - -* Tabs are now correctly changed into spaces. Previously, only - the first tab was converted. In code blocks, the second one was too, - but was not always correctly aligned. - -* Fixed a bug where a tab character inserted after a quote on the same - line could add a slash before the quotes. - - This is "before" [tab] and "after" a tab. - - Previously gave this result: - -

This is \"before\" [tab] and "after" a tab.

- -* Removed a call to `htmlentities`. This fixes a bug where multibyte - characters present in the title of a link reference could lead to - invalid utf-8 characters. - -* Changed a regular expression in `_TokenizeHTML` that could lead to - a segmentation fault with PHP 4.3.8 on Linux. - -* Fixed some notices that could show up if PHP error reporting - E_NOTICE flag was set. - - -Copyright and License ---------------------- - -Copyright (c) 2004-2006 Michel Fortin - -All rights reserved. - -Based on Markdown -Copyright (c) 2003-2005 John Gruber - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -* Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -* Neither the name "Markdown" nor the names of its contributors may - be used to endorse or promote products derived from this software - without specific prior written permission. - -This software is provided by the copyright holders and contributors "as -is" and any express or implied warranties, including, but not limited -to, the implied warranties of merchantability and fitness for a -particular purpose are disclaimed. In no event shall the copyright owner -or contributors be liable for any direct, indirect, incidental, special, -exemplary, or consequential damages (including, but not limited to, -procurement of substitute goods or services; loss of use, data, or -profits; or business interruption) however caused and on any theory of -liability, whether in contract, strict liability, or tort (including -negligence or otherwise) arising in any way out of the use of this -software, even if advised of the possibility of such damage. diff --git a/markdown.php b/markdown.php index 426e7fc..271f6d4 100644 --- a/markdown.php +++ b/markdown.php @@ -1,8 +1,8 @@ # @@ -12,7 +12,8 @@ # -define( 'MARKDOWN_VERSION', "1.0.1oo" ); # Fri 19 May 2006 +define( 'MARKDOWN_VERSION', "1.0.1oo" ); # Fri 19 May 2006 +define( 'MARKDOWNEXTRA_VERSION', "1.0.1oo" ); # Fri 19 May 2006 # @@ -38,7 +39,7 @@ define( 'MARKDOWN_WP_COMMENTS', true ); ### Standard Function Interface ### -define( 'MARKDOWN_PARSER_CLASS', 'Markdown_Parser' ); +define( 'MARKDOWN_PARSER_CLASS', 'MarkdownExtra_Parser' ); function Markdown($text) { # @@ -59,7 +60,7 @@ function Markdown($text) { ### WordPress Plugin Interface ### /* -Plugin Name: Markdown +Plugin Name: Markdown Extra Plugin URI: http://www.michelf.com/projects/php-markdown/ Description:
Markdown syntax allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by John Gruber. More... Version: 1.0.1oo @@ -140,15 +141,15 @@ if (isset($wp_version)) { function identify_modifier_markdown() { return array( - 'name' => 'markdown', - 'type' => 'modifier', - 'nicename' => 'Markdown', - 'description' => 'A text-to-HTML conversion tool for web writers', - 'authors' => 'Michel Fortin and John Gruber', - 'licence' => 'GPL', - 'version' => MARKDOWN_VERSION, - 'help' => 'Markdown syntax allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by John Gruber. More...' - ); + 'name' => 'markdown', + 'type' => 'modifier', + 'nicename' => 'PHP Markdown Extra', + 'description' => 'A text-to-HTML conversion tool for web writers', + 'authors' => 'Michel Fortin and John Gruber', + 'licence' => 'GPL', + 'version' => MARKDOWNEXTRA_VERSION, + 'help' => 'Markdown syntax allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by John Gruber. More...', + ); } @@ -1302,16 +1303,974 @@ class Markdown_Parser { } +# +# Markdown Extra Parser Class +# + +class MarkdownExtra_Parser extends Markdown_Parser { + + # Extra hash used during transformation. + var $html_hashes = array(); + + + function MarkdownExtra_Parser() { + # + # Constructor function. Initialize the parser object. + # + # Add extra escapable characters before parent constructor + # initialize the table. + $this->escape_chars .= ':|'; + + parent::Markdown_Parser(); + } + + + function transform($text) { + # + # Added clear to the new $html_hashes, reordered `hashHTMLBlocks` before + # blank line stripping and added extra parameter to `runBlockGamut`. + # + # Clear the global hashes. If we don't clear these, you get conflicts + # from other articles when generating a page which contains more than + # one article (e.g. an index page that shows the N most recent + # articles): + $this->urls = array(); + $this->titles = array(); + $this->html_blocks = array(); + $this->html_hashes = array(); + + # Standardize line endings: + # DOS to Unix and Mac to Unix + $text = str_replace(array("\r\n", "\r"), "\n", $text); + + # Make sure $text ends with a couple of newlines: + $text .= "\n\n"; + + # Convert all tabs to spaces. + $text = $this->detab($text); + + # Turn block-level HTML blocks into hash entries + $text = $this->hashHTMLBlocks($text); + + # Strip any lines consisting only of spaces and tabs. + # This makes subsequent regexen easier to write, because we can + # match consecutive blank lines with /\n+/ instead of something + # contorted like /[ \t]*\n+/ . + $text = preg_replace('/^[ \t]+$/m', '', $text); + + # Strip link definitions, store in hashes. + $text = $this->stripLinkDefinitions($text); + + $text = $this->runBlockGamut($text, false); + + $text = $this->unescapeSpecialChars($text); + + return $text . "\n"; + } + + + + ### HTML Block Parser ### + + # Tags that are always treated as block tags: + var $block_tags = + 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|form|fieldset|iframe|hr|legend'; + + # Tags treated as block tags only if the opening tag is alone on it's line: + var $context_block_tags = 'script|noscript|math|ins|del'; + + # Tags where markdown="1" default to span mode: + var $contain_span_tags = 'p|h[1-6]|li|dd|dt|td|th|legend'; + + # Tags which must not have their contents modified, no matter where + # they appear: + var $clean_tags = 'script|math'; + + # Tags that do not need to be closed. + var $auto_close_tags = 'hr|img'; + + + function hashHTMLBlocks($text) { + # + # Hashify HTML Blocks and "clean tags". + # + # We only want to do this for block-level HTML tags, such as headers, + # lists, and tables. That's because we still want to wrap

s around + # "paragraphs" that are wrapped in non-block-level tags, such as anchors, + # phrase emphasis, and spans. The list of tags we're looking for is + # hard-coded. + # + # This works by calling _HashHTMLBlocks_InMarkdown, which then calls + # _HashHTMLBlocks_InHTML when it encounter block tags. When the markdown="1" + # attribute is found whitin a tag, _HashHTMLBlocks_InHTML calls back + # _HashHTMLBlocks_InMarkdown to handle the Markdown syntax within the tag. + # These two functions are calling each other. It's recursive! + # + # + # Call the HTML-in-Markdown hasher. + # + list($text, ) = $this->_hashHTMLBlocks_inMarkdown($text); + + return $text; + } + function _hashHTMLBlocks_inMarkdown($text, $indent = 0, + $enclosing_tag = '', $span = false) + { + # + # Parse markdown text, calling _HashHTMLBlocks_InHTML for block tags. + # + # * $indent is the number of space to be ignored when checking for code + # blocks. This is important because if we don't take the indent into + # account, something like this (which looks right) won't work as expected: + # + #

+ #
+ # Hello World. <-- Is this a Markdown code block or text? + #
<-- Is this a Markdown code block or a real tag? + #
+ # + # If you don't like this, just don't indent the tag on which + # you apply the markdown="1" attribute. + # + # * If $enclosing_tag is not empty, stops at the first unmatched closing + # tag with that name. Nested tags supported. + # + # * If $span is true, text inside must treated as span. So any double + # newline will be replaced by a single newline so that it does not create + # paragraphs. + # + # Returns an array of that form: ( processed text , remaining text ) + # + if ($text === '') return array('', ''); + + # Regex to check for the presense of newlines around a block tag. + $newline_match_before = '/(?:^\n?|\n\n)*$/'; + $newline_match_after = + '{ + ^ # Start of text following the tag. + (?:[ ]*)? # Optional comment. + [ ]*\n # Must be followed by newline. + }xs'; + + # Regex to match any tag. + $block_tag_match = + '{ + ( # $2: Capture hole tag. + block_tags.' | + '.$this->context_block_tags.' | + '.$this->clean_tags.' | + (?!\s)'.$enclosing_tag.' + ) + \s* # Whitespace. + (?: + ".*?" | # Double quotes (can contain `>`) + \'.*?\' | # Single quotes (can contain `>`) + .+? # Anything but quotes and `>`. + )*? + > # End of tag. + | + # HTML Comment + | + <\? .*? \?> # Processing instruction + | + # CData Block + ) + }xs'; + + + $depth = 0; # Current depth inside the tag tree. + $parsed = ""; # Parsed text that will be returned. + + # + # Loop through every tag until we find the closing tag of the parent + # or loop until reaching the end of text if no parent tag specified. + # + do { + # + # Split the text using the first $tag_match pattern found. + # Text before pattern will be first in the array, text after + # pattern will be at the end, and between will be any catches made + # by the pattern. + # + $parts = preg_split($block_tag_match, $text, 2, + PREG_SPLIT_DELIM_CAPTURE); + + # If in Markdown span mode, replace any multiple newlines that would + # trigger a new paragraph. + if ($span) { + $parts[0] = preg_replace('/\n\n/', "\n", $parts[0]); + } + + $parsed .= $parts[0]; # Text before current tag. + + # If end of $text has been reached. Stop loop. + if (count($parts) < 3) { + $text = ""; + break; + } + + $tag = $parts[1]; # Tag to handle. + $text = $parts[2]; # Remaining text after current tag. + + # + # Check for: Tag inside code block or span + # + if (# Find current paragraph + preg_match('/(?>^\n?|\n\n)((?>.\n?)+?)$/', $parsed, $matches) && + ( + # Then match in it either a code block... + preg_match('/^ {'.($indent+4).'}.*(?>\n {'.($indent+4).'}.*)*'. + '(?!\n)$/', $matches[1], $x) || + # ...or unbalenced code span markers. (the regex matches balenced) + !preg_match('/^(?>[^`]+|(`+)(?>[^`]+|(?!\1[^`])`)*?\1(?!`))*$/s', + $matches[1]) + )) + { + # Tag is in code block or span and may not be a tag at all. So we + # simply skip the first char (should be a `<`). + $parsed .= $tag{0}; + $text = substr($tag, 1) . $text; # Put back $tag minus first char. + } + # + # Check for: Opening Block level tag or + # Opening Content Block tag (like ins and del) + # used as a block tag (tag is alone on it's line). + # + else if (preg_match("{^<(?:$this->block_tags)\b}", $tag) || + ( preg_match("{^<(?:$this->context_block_tags)\b}", $tag) && + preg_match($newline_match_before, $parsed) && + preg_match($newline_match_after, $text) ) + ) + { + # Need to parse tag and following text using the HTML parser. + list($block_text, $text) = + $this->_hashHTMLBlocks_inHTML($tag . $text, + "_hashHTMLBlocks_hashBlock", TRUE); + + # Make sure it stays outside of any paragraph by adding newlines. + $parsed .= "\n\n$block_text\n\n"; + } + # + # Check for: Clean tag (like script, math) + # HTML Comments, processing instructions. + # + else if (preg_match("{^<(?:$this->clean_tags)\b}", $tag) || + $tag{1} == '!' || $tag{1} == '?') + { + # Need to parse tag and following text using the HTML parser. + # (don't check for markdown attribute) + list($block_text, $text) = + $this->_hashHTMLBlocks_inHTML($tag . $text, + "_hashHTMLBlocks_hashClean", FALSE); + + $parsed .= $block_text; + } + # + # Check for: Tag with same name as enclosing tag. + # + else if ($enclosing_tag !== '' && + # Same name as enclosing tag. + preg_match("{^= 0); + + return array($parsed, $text); + } + function _hashHTMLBlocks_inHTML($text, $hash_method, $md_attr) { + # + # Parse HTML, calling _HashHTMLBlocks_InMarkdown for block tags. + # + # * Calls $hash_method to convert any blocks. + # * Stops when the first opening tag closes. + # * $md_attr indicate if the use of the `markdown="1"` attribute is allowed. + # (it is not inside clean tags) + # + # Returns an array of that form: ( processed text , remaining text ) + # + if ($text === '') return array('', ''); + + # Regex to match `markdown` attribute inside of a tag. + $markdown_attr_match = ' + { + \s* # Eat whitespace before the `markdown` attribute + markdown + \s*=\s* + (["\']) # $1: quote delimiter + (.*?) # $2: attribute value + \1 # matching delimiter + }xs'; + + # Regex to match any tag. + $tag_match = '{ + ( # $2: Capture hole tag. + `) + \'.*?\' | # Single quotes (can contain `>`) + .+? # Anything but quotes and `>`. + )*? + > # End of tag. + | + # HTML Comment + | + <\? .*? \?> # Processing instruction + | + # CData Block + ) + }xs'; + + $original_text = $text; # Save original text in case of faliure. + + $depth = 0; # Current depth inside the tag tree. + $block_text = ""; # Temporary text holder for current text. + $parsed = ""; # Parsed text that will be returned. + + # + # Get the name of the starting tag. + # + if (preg_match("/^<([\w:$]*)\b/", $text, $matches)) + $base_tag_name = $matches[1]; + + # + # Loop through every tag until we find the corresponding closing tag. + # + do { + # + # Split the text using the first $tag_match pattern found. + # Text before pattern will be first in the array, text after + # pattern will be at the end, and between will be any catches made + # by the pattern. + # + $parts = preg_split($tag_match, $text, 2, PREG_SPLIT_DELIM_CAPTURE); + + if (count($parts) < 3) { + # + # End of $text reached with unbalenced tag(s). + # In that case, we return original text unchanged and pass the + # first character as filtered to prevent an infinite loop in the + # parent function. + # + return array($original_text{0}, substr($original_text, 1)); + } + + $block_text .= $parts[0]; # Text before current tag. + $tag = $parts[1]; # Tag to handle. + $text = $parts[2]; # Remaining text after current tag. + + # + # Check for: Auto-close tag (like
) + # Comments and Processing Instructions. + # + if (preg_match("{^auto_close_tags)\b}", $tag) || + $tag{1} == '!' || $tag{1} == '?') + { + # Just add the tag to the block as if it was text. + $block_text .= $tag; + } + else { + # + # Increase/decrease nested tag count. Only do so if + # the tag's name match base tag's. + # + if (preg_match("{^mode = $attr_matches[2]; + $span_mode = $this->mode == 'span' || $this->mode != 'block' && + preg_match("{^<(?:$this->contain_span_tags)\b}", $tag); + + # Calculate indent before tag. + preg_match('/(?:^|\n)( *?)(?! ).*?$/', $block_text, $matches); + $indent = strlen($matches[1]); + + # End preceding block with this tag. + $block_text .= $tag; + $parsed .= $this->$hash_method($block_text, $span_mode); + + # Get enclosing tag name for the ParseMarkdown function. + preg_match('/^<([\w:$]*)\b/', $tag, $matches); + $tag_name = $matches[1]; + + # Parse the content using the HTML-in-Markdown parser. + list ($block_text, $text) + = $this->_hashHTMLBlocks_inMarkdown($text, $indent, + $tag_name, $span_mode); + + # Outdent markdown text. + if ($indent > 0) { + $block_text = preg_replace("/^[ ]{1,$indent}/m", "", + $block_text); + } + + # Append tag content to parsed text. + if (!$span_mode) $parsed .= "\n\n$block_text\n\n"; + else $parsed .= "$block_text"; + + # Start over a new block. + $block_text = ""; + } + else $block_text .= $tag; + } + + } while ($depth > 0); + + # + # Hash last block text that wasn't processed inside the loop. + # + $parsed .= $this->$hash_method($block_text); + + return array($parsed, $text); + } + function _hashHTMLBlocks_HashBlock($text) { + $key = md5($text); + $this->html_hashes[$key] = $text; + $this->html_blocks[$key] = $text; + return $key; # String that will replace the tag. + } + function _hashHTMLBlocks_HashClean($text) { + $key = md5($text); + $this->html_hashes[$key] = $text; + return $key; # String that will replace the clean tag. + } + + + function hashBlock($text) { + # + # Called whenever a tag must be hashed when a function insert a block-level + # tag in $text, it pass through this function and is automaticaly escaped, + # which remove the need to call _HashHTMLBlocks at every step. + # + # Swap back any tag hash found in $text so we do not have to _UnhashTags + # multiple times at the end. + $text = $this->unhashTags($text); + + # Then hash the block as usual. + $text = $this->_hashHTMLBlocks_HashBlock($text); + + return $text; + } + + + function runBlockGamut($text, $hash_html_blocks = true) { + # + # Redefined to add definition lists and move HTML block hashing at the start. + # + if ($hash_html_blocks) { + # We need to escape raw HTML in Markdown source before doing anything + # else. This need to be done for each block, and not only at the + # begining in the Markdown function since hashed blocks can be part of + # a list item and could have been indented. Indented blocks would have + # been seen as a code block in previous pass of _HashHTMLBlocks. + $text = $this->hashHTMLBlocks($text); + } + + $text = $this->doHeaders($text); + $text = $this->doTables($text); + + # Do Horizontal Rules: + $text = preg_replace( + array('{^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$}mx', + '{^[ ]{0,2}([ ]? -[ ]?){3,}[ \t]*$}mx', + '{^[ ]{0,2}([ ]? _[ ]?){3,}[ \t]*$}mx'), + $this->hashBlock("\nempty_element_suffix\n"), $text); + + $text = $this->doLists($text); + $text = $this->doDefLists($text); + $text = $this->doCodeBlocks($text); + $text = $this->doBlockQuotes($text); + $text = $this->formParagraphs($text); + + return $text; + } + + + function doHeaders($text) { + # + # Redefined to add id attribute support. + # + # Setext-style headers: + # Header 1 {#header1} + # ======== + # + # Header 2 {#header2} + # -------- + # + $text = preg_replace_callback( + '{ (^.+?) (?:[ ]+\{\#([-_:a-zA-Z0-9]+)\})? [ \t]*\n=+[ \t]*\n+ }mx', + array(&$this, '_doHeaders_callback_setext_h1'), $text); + $text = preg_replace_callback( + '{ (^.+?) (?:[ ]+\{\#([-_:a-zA-Z0-9]+)\})? [ \t]*\n-+[ \t]*\n+ }mx', + array(&$this, '_doHeaders_callback_setext_h2'), $text); + + # atx-style headers: + # # Header 1 {#header1} + # ## Header 2 {#header2} + # ## Header 2 with closing hashes ## {#header3} + # ... + # ###### Header 6 {#header2} + # + $text = preg_replace_callback('{ + ^(\#{1,6}) # $1 = string of #\'s + [ \t]* + (.+?) # $2 = Header text + [ \t]* + \#* # optional closing #\'s (not counted) + (?:[ ]+\{\#([-_:a-zA-Z0-9]+)\}[ ]*)? # id attribute + \n+ + }xm', + array(&$this, '_doHeaders_callback_atx'), $text); + + return $text; + } + function _doHeaders_attr($attr) { + if (empty($attr)) return ""; + return " id=\"$attr\""; + } + function _doHeaders_callback_setext_h1($matches) { + $attr = $this->_doHeaders_attr($id =& $matches[2]); + $block = "".$this->runSpanGamut($matches[1]).""; + return $this->hashBlock($block) . "\n\n"; + } + function _doHeaders_callback_setext_h2($matches) { + $attr = $this->_doHeaders_attr($id =& $matches[2]); + $block = "".$this->runSpanGamut($matches[1]).""; + return $this->hashBlock($block) . "\n\n"; + } + function _doHeaders_callback_atx($matches) { + $level = strlen($matches[1]); + $attr = $this->_doHeaders_attr($id =& $matches[3]); + $block = "".$this->runSpanGamut($matches[2]).""; + return $this->hashBlock($block) . "\n\n"; + } + + + function doTables($text) { + # + # Form HTML tables. + # + $less_than_tab = $this->tab_width - 1; + # + # Find tables with leading pipe. + # + # | Header 1 | Header 2 + # | -------- | -------- + # | Cell 1 | Cell 2 + # | Cell 3 | Cell 4 + # + $text = preg_replace_callback(' + { + ^ # Start of a line + [ ]{0,'.$less_than_tab.'} # Allowed whitespace. + [|] # Optional leading pipe (present) + (.+) \n # $1: Header row (at least one pipe) + + [ ]{0,'.$less_than_tab.'} # Allowed whitespace. + [|] ([ ]*[-:]+[-| :]*) \n # $2: Header underline + + ( # $3: Cells + (?: + [ ]* # Allowed whitespace. + [|] .* \n # Row content. + )* + ) + (?=\n|\Z) # Stop at final double newline. + }xm', + array(&$this, '_doTable_leadingPipe_callback'), $text); + + # + # Find tables without leading pipe. + # + # Header 1 | Header 2 + # -------- | -------- + # Cell 1 | Cell 2 + # Cell 3 | Cell 4 + # + $text = preg_replace_callback(' + { + ^ # Start of a line + [ ]{0,'.$less_than_tab.'} # Allowed whitespace. + (\S.*[|].*) \n # $1: Header row (at least one pipe) + + [ ]{0,'.$less_than_tab.'} # Allowed whitespace. + ([-:]+[ ]*[|][-| :]*) \n # $2: Header underline + + ( # $3: Cells + (?: + .* [|] .* \n # Row content + )* + ) + (?=\n|\Z) # Stop at final double newline. + }xm', + array(&$this, '_DoTable_callback'), $text); + + return $text; + } + function _doTable_leadingPipe_callback($matches) { + $head = $matches[1]; + $underline = $matches[2]; + $content = $matches[3]; + + # Remove leading pipe for each row. + $content = preg_replace('/^ *[|]/m', '', $content); + + return $this->_doTable_callback(array($matches[0], $head, $underline, $content)); + } + function _doTable_callback($matches) { + $head = $matches[1]; + $underline = $matches[2]; + $content = $matches[3]; + + # Remove any tailing pipes for each line. + $head = preg_replace('/[|] *$/m', '', $head); + $underline = preg_replace('/[|] *$/m', '', $underline); + $content = preg_replace('/[|] *$/m', '', $content); + + # Reading alignement from header underline. + $separators = preg_split('/ *[|] */', $underline); + foreach ($separators as $n => $s) { + if (preg_match('/^ *-+: *$/', $s)) $attr[$n] = ' align="right"'; + else if (preg_match('/^ *:-+: *$/', $s))$attr[$n] = ' align="center"'; + else if (preg_match('/^ *:-+ *$/', $s)) $attr[$n] = ' align="left"'; + else $attr[$n] = ''; + } + + # Creating code spans before splitting the row is an easy way to + # handle a code span containg pipes. + $head = $this->doCodeSpans($head); + $headers = preg_split('/ *[|] */', $head); + $col_count = count($headers); + + # Write column headers. + $text = "\n"; + $text .= "\n"; + $text .= "\n"; + foreach ($headers as $n => $header) + $text .= " ".$this->runSpanGamut(trim($header))."\n"; + $text .= "\n"; + $text .= "\n"; + + # Split content by row. + $rows = explode("\n", trim($content, "\n")); + + $text .= "\n"; + foreach ($rows as $row) { + # Creating code spans before splitting the row is an easy way to + # handle a code span containg pipes. + $row = $this->doCodeSpans($row); + + # Split row by cell. + $row_cells = preg_split('/ *[|] */', $row, $col_count); + $row_cells = array_pad($row_cells, $col_count, ''); + + $text .= "\n"; + foreach ($row_cells as $n => $cell) + $text .= " ".$this->runSpanGamut(trim($cell))."\n"; + $text .= "\n"; + } + $text .= "\n"; + $text .= "
"; + + return $this->hashBlock($text) . "\n"; + } + + + # + # Redefined callbacks that should now return hashed output. + # + function _doLists_callback_top($matches) { + # Calling the nested variant as there is no point in trimming + # whitespace when hashing output blocks. + return $this->_doLists_callback_nested($matches); + } + function _doLists_callback_nested($matches) { + $block = parent::_doLists_callback_nested($matches); + return "\n" . $this->hashBlock(trim($block)) . "\n\n"; + } + + function _doCodeBlocks_callback($matches) { + $result = parent::_doCodeBlocks_callback($matches); + return "\n\n" . $this->hashBlock(trim($result)) . "\n\n"; + } + + function _doBlockQuotes_callback($matches) { + $result = parent::_doBlockQuotes_callback($matches); + return $this->hashBlock(trim($result)) . "\n\n"; + } + + + + function doDefLists($text) { + # + # Form HTML definition lists. + # + $less_than_tab = $this->tab_width - 1; + + # Re-usable pattern to match any entire dl list: + $whole_list = ' + ( # $1 = whole list + ( # $2 + [ ]{0,'.$less_than_tab.'} + ((?>.*\S.*\n)+) # $3 = defined term + \n? + [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition + ) + (?s:.+?) + ( # $4 + \z + | + \n{2,} + (?=\S) + (?! # Negative lookahead for another term + [ ]{0,'.$less_than_tab.'} + (?: \S.*\n )+? # defined term + \n? + [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition + ) + (?! # Negative lookahead for another definition + [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition + ) + ) + ) + '; // mx + + $text = preg_replace_callback('{ + (?:(?<=\n\n)|\A\n?) + '.$whole_list.' + }mx', + array(&$this, '_doDefLists_callback'), $text); + + return $text; + } + function _doDefLists_callback($matches) { + # Re-usable patterns to match list item bullets and number markers: + $list = $matches[1]; + + # Turn double returns into triple returns, so that we can make a + # paragraph for the last item in a list, if necessary: + $result = trim($this->processDefListItems($list)); + $result = "
\n" . $result . "\n
"; + return $this->hashBlock($result) . "\n\n"; + } + + + function processDefListItems($list_str) { + # + # Process the contents of a single definition list, splitting it + # into individual term and definition list items. + # + $less_than_tab = $this->tab_width - 1; + + # trim trailing blank lines: + $list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str); + + # Process definition terms. + $list_str = preg_replace_callback('{ + (?:\n\n+|\A\n?) # leading line + ( # definition terms = $1 + [ ]{0,'.$less_than_tab.'} # leading whitespace + (?![:][ ]|[ ]) # negative lookahead for a definition + # mark (colon) or more whitespace. + (?: \S.* \n)+? # actual term (not whitespace). + ) + (?=\n?[ ]{0,3}:[ ]) # lookahead for following line feed + # with a definition mark. + }xm', + array(&$this, '_ProcessDefListItems_callback_dt'), $list_str); + + # Process actual definitions. + $list_str = preg_replace_callback('{ + \n(\n+)? # leading line = $1 + [ ]{0,'.$less_than_tab.'} # whitespace before colon + [:][ ]+ # definition mark (colon) + ((?s:.+?)) # definition text = $2 + (?= \n+ # stop at next definition mark, + (?: # next term or end of text + [ ]{0,'.$less_than_tab.'} [:][ ] | +
| \z + ) + ) + }xm', + array(&$this, '_ProcessDefListItems_callback_dd'), $list_str); + + return $list_str; + } + function _processDefListItems_callback_dt($matches) { + $terms = explode("\n", trim($matches[1])); + $text = ''; + foreach ($terms as $term) { + $term = $this->runSpanGamut(trim($term)); + $text .= "\n
" . $term . "
"; + } + return $text . "\n"; + } + function _processDefListItems_callback_dd($matches) { + $leading_line = $matches[1]; + $def = $matches[2]; + + if ($leading_line || preg_match('/\n{2,}/', $def)) { + $def = $this->runBlockGamut($this->outdent($def . "\n\n")); + $def = "\n". $def ."\n"; + } + else { + $def = rtrim($def); + $def = $this->runSpanGamut($this->outdent($def)); + } + + return "\n
" . $def . "
\n"; + } + + + function doItalicsAndBold($text) { + # + # Redefined to change emphasis by underscore behaviour so that it does not + # work in the middle of a word. + # + # must go first: + $text = preg_replace(array( + '{ + ( (? + [^_]+? # Anthing not em markers. + | + # Balence any regular _ emphasis inside. + (? + [^*]+? # Anthing not em markers. + | + # Balence any regular * emphasis inside. + \* (?=\S) (?! \*) (.+?) (?<=\S) \* + )+? + ) + (?<=\S) \*\* # End mark not preceded by whitespace. + }sx', + ), + '\2', $text); + # Then : + $text = preg_replace(array( + '{ ( (?\2', $text); + + return $text; + } + + + function formParagraphs($text) { + # + # Params: + # $text - string to process with html

tags + # + # Strip leading and trailing lines: + $text = preg_replace(array('/\A\n+/', '/\n+\z/'), '', $text); + + $grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY); + + # + # Wrap

tags and unhashify HTML blocks + # + foreach ($grafs as $key => $value) { + $value = trim($this->runSpanGamut($value)); + + # Check if this should be enclosed in a paragraph. + # Text equaling to a clean tag hash are not enclosed. + # Text starting with a block tag hash are not either. + $clean_key = $value; + $block_key = substr($value, 0, 32); + + $is_p = (!isset($this->html_blocks[$block_key]) && + !isset($this->html_hashes[$clean_key])); + + if ($is_p) { + $value = "

$value

"; + } + $grafs[$key] = $value; + } + + # Join grafs in one text, then unhash HTML tags. + $text = implode("\n\n", $grafs); + + # Finish by removing any tag hashes still present in $text. + $text = $this->unhashTags($text); + + return $text; + } + + + function unhashTags($text) { + # + # Swap back in all the tags hashed by _HashHTMLBlocks. + # + return str_replace(array_keys($this->html_hashes), + array_values($this->html_hashes), $text); + } + +} + + /* -PHP Markdown -============ +PHP Markdown Extra +================== Description ----------- -This is a PHP translation of the original Markdown formatter written in -Perl by John Gruber. +This is a PHP port of the original Markdown formatter written in Perl +by John Gruber. This special "Extra" version of PHP Markdown features +further enhancements to the syntax for making additional constructs +such as tables and definition list. Markdown is a text-to-HTML filter; it translates an easy-to-read / easy-to-write structured text format into HTML. Markdown's text format @@ -1342,22 +2301,24 @@ expected; (3) the output Markdown actually produced. Version History --------------- -See the readme file for detailed release notes for this version. +See Readme file for details. 1.0.1oo (19 May 2006) -* Converted PHP Markdown to a object-oriented design. +* Converted PHP Markdown and PHP Markdown Extra to a object-oriented design. -1.0.1c (9 Dec 2005) +1.0.1 (9 December 2005) -1.0.1b (6 Jun 2005) +1.0 (5 September 2005) -1.0.1a (15 Apr 2005) +1.0b4 (1 August 2005) -1.0.1 (16 Dec 2004) +1.0b3 (29 July 2005) -1.0 (21 Aug 2004) +1.0b2 (26 July 2005) + +1.0b1 (25 July 2005) Author & Contributors @@ -1377,6 +2338,7 @@ Copyright (c) 2004-2006 Michel Fortin All rights reserved. +Based on Markdown Copyright (c) 2003-2004 John Gruber All rights reserved. @@ -1409,4 +2371,4 @@ negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage. */ -?> +?> \ No newline at end of file