diff --git a/blog/wp-content/plugins/markdown/License.text b/blog/wp-content/plugins/markdown/License.text old mode 100644 new mode 100755 index ea90c49..4d6bf8b --- a/blog/wp-content/plugins/markdown/License.text +++ b/blog/wp-content/plugins/markdown/License.text @@ -1,4 +1,4 @@ -PHP Markdown +PHP Markdown & Extra Copyright (c) 2004-2009 Michel Fortin All rights reserved. diff --git a/blog/wp-content/plugins/markdown/PHP Markdown Extra Readme.text b/blog/wp-content/plugins/markdown/PHP Markdown Extra Readme.text new file mode 100755 index 0000000..b72ee99 --- /dev/null +++ b/blog/wp-content/plugins/markdown/PHP Markdown Extra Readme.text @@ -0,0 +1,786 @@ +PHP Markdown Extra +================== + +Version 1.2.4 - Sat 10 Oct 2009 + +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. + + [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. + +3. To post Markdown content, you'll first have to disable the + "visual" editor in the User section of WordPress. + +You can configure PHP Markdown to not apply to the comments on your +WordPress weblog. See the "Configuration" section below. + +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 a limitation of WordPress. If your old entries +are written in HTML (as opposed to another formatting syntax, like +Textile), they'll probably stay fine after installing Markdown. + + +### bBlog ### + +PHP Markdown also works with [bBlog][bb]. + + [bb]: http://www.bblog.com/ + +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 + +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 in TextPattern ### + +[TextPattern][tp] use [Textile][tx] to format your text. You can +replace Textile by Markdown in TextPattern without having to change +any code by using the *Texitle Compatibility Mode*. This may work +with other software that expect Textile too. + + [tx]: http://www.textism.com/tools/textile/ + [tp]: http://www.textpattern.com/ + +1. Rename the "markdown.php" file to "classTextile.php". This will + make PHP Markdown behave as if it was the actual Textile parser. + +2. Replace the "classTextile.php" file TextPattern installed in your + web directory. It can be found in the "lib" directory: + + (site home)/textpattern/lib/ + +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://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. + + +### Updating Markdown in Other Programs ### + +Many web applications now ship with PHP Markdown, or have plugins to +perform the conversion to HTML. You can update PHP Markdown -- or +replace it with PHP Markdown Extra -- in many of these programs by +swapping the old "markdown.php" file for the new one. + +Here is a short non-exhaustive list of some programs and where they +hide the "markdown.php" file. + +| Program | Path to Markdown +| ------- | ---------------- +| [Pivot][] | `(site home)/pivot/includes/markdown/` + +If you're unsure if you can do this with your application, ask the +developer, or wait for the developer to update his application or +plugin with the new version of PHP Markdown. + + [Pivot]: http://pivotlog.net/ + + +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 "MARKDOWN_EMPTY_ELEMENT_SUFFIX" +definition 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 +`MARKDOWN_WP_POSTS` or `MARKDOWN_WP_COMMENTS` definitions 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.1n (10 Oct 2009): + +* Enabled reference-style shortcut links. Now you can write reference-style + links with less brakets: + + This is [my website]. + + [my website]: http://example.com/ + + This was added in the 1.0.2 betas, but commented out in the 1.0.1 branch, + waiting for the feature to be officialized. [But half of the other Markdown + implementations are supporting this syntax][half], so it makes sense for + compatibility's sake to allow it in PHP Markdown too. + + [half]: http://babelmark.bobtfish.net/?markdown=This+is+%5Bmy+website%5D.%0D%0A%09%09%0D%0A%5Bmy+website%5D%3A+http%3A%2F%2Fexample.com%2F%0D%0A&src=1&dest=2 + +* Now accepting many valid email addresses in autolinks that were + previously rejected, such as: + + + + <"abc@def"@example.com> + <"Fred Bloggs"@example.com> + + +* Now accepting spaces in URLs for inline and reference-style links. Such + URLs need to be surrounded by angle brakets. For instance: + + [link text]( "optional title") + + [link text][ref] + [ref]: "optional title" + + There is still a quirk which may prevent this from working correctly with + relative URLs in inline-style links however. + +* Fix for adjacent list of different kind where the second list could + end as a sublist of the first when not separated by an empty line. + +* Fixed a bug where inline-style links wouldn't be recognized when the link + definition contains a line break between the url and the title. + +* Fixed a bug where tags where the name contains an underscore aren't parsed + correctly. + +* Fixed some corner-cases mixing underscore-ephasis and asterisk-emphasis. + + +Extra 1.2.4: + +* Fixed a problem where unterminated tags in indented code blocks could + prevent proper escaping of characaters in the code block. + + +Extra 1.2.3 (31 Dec 2008): + +* In WordPress pages featuring more than one post, footnote id prefixes are + now automatically applied with the current post ID to avoid clashes + between footnotes belonging to different posts. + +* Fix for a bug introduced in Extra 1.2 where block-level HTML tags where + not detected correctly, thus the addition of erroneous `

` tags and + interpretation of their content as Markdown-formatted instead of + HTML-formatted. + + +Extra 1.2.2 (21 Jun 2008): + +* Fixed a problem where abbreviation definitions, footnote + definitions and link references were stripped inside + fenced code blocks. + +* Fixed a bug where characters such as `"` in abbreviation + definitions weren't properly encoded to HTML entities. + +* Fixed a bug where double quotes `"` were not correctly encoded + as HTML entities when used inside a footnote reference id. + + +1.0.1m (21 Jun 2008): + +* Lists can now have empty items. + +* Rewrote the emphasis and strong emphasis parser to fix some issues + with odly placed and overlong markers. + + +Extra 1.2.1 (27 May 2008): + +* Fixed a problem where Markdown headers and horizontal rules were + transformed into their HTML equivalent inside fenced code blocks. + + +Extra 1.2 (11 May 2008): + +* Added fenced code block syntax which don't require indentation + and can start and end with blank lines. A fenced code block + starts with a line of consecutive tilde (~) and ends on the + next line with the same number of consecutive tilde. Here's an + example: + + ~~~~~~~~~~~~ + Hello World! + ~~~~~~~~~~~~ + +* Rewrote parts of the HTML block parser to better accomodate + fenced code blocks. + +* Footnotes may now be referenced from within another footnote. + +* Added programatically-settable parser property `predef_attr` for + predefined attribute definitions. + +* Fixed an issue where an indented code block preceded by a blank + line containing some other whitespace would confuse the HTML + block parser into creating an HTML block when it should have + been code. + + +1.0.1l (11 May 2008): + +* Now removing the UTF-8 BOM at the start of a document, if present. + +* Now accepting capitalized URI schemes (such as HTTP:) in automatic + links, such as ``. + +* Fixed a problem where `` was seen as a horizontal + rule instead of an automatic link. + +* Fixed an issue where some characters in Markdown-generated HTML + attributes weren't properly escaped with entities. + +* Fix for code blocks as first element of a list item. Previously, + this didn't create any code block for item 2: + + * Item 1 (regular paragraph) + + * Item 2 (code block) + +* A code block starting on the second line of a document wasn't seen + as a code block. This has been fixed. + +* Added programatically-settable parser properties `predef_urls` and + `predef_titles` for predefined URLs and titles for reference-style + links. To use this, your PHP code must call the parser this way: + + $parser = new Markdwon_Parser; + $parser->predef_urls = array('linkref' => 'http://example.com'); + $html = $parser->transform($text); + + You can then use the URL as a normal link reference: + + [my link][linkref] + [my link][linkRef] + + Reference names in the parser properties *must* be lowercase. + Reference names in the Markdown source may have any case. + +* Added `setup` and `teardown` methods which can be used by subclassers + as hook points to arrange the state of some parser variables before and + after parsing. + + +Extra 1.1.7 (26 Sep 2007): + +1.0.1k (26 Sep 2007): + +* Fixed a problem introduced in 1.0.1i where three or more identical + uppercase letters, as well as a few other symbols, would trigger + a horizontal line. + + +Extra 1.1.6 (4 Sep 2007): + +1.0.1j (4 Sep 2007): + +* Fixed a problem introduced in 1.0.1i where the closing `code` and + `pre` tags at the end of a code block were appearing in the wrong + order. + +* Overriding configuration settings by defining constants from an + external before markdown.php is included is now possible without + producing a PHP warning. + + +Extra 1.1.5 (31 Aug 2007): + +1.0.1i (31 Aug 2007): + +* Fixed a problem where an escaped backslash before a code span + would prevent the code span from being created. This should now + work as expected: + + Litteral backslash: \\`code span` + +* Overall speed improvements, especially with long documents. + + +Extra 1.1.4 (3 Aug 2007): + +1.0.1h (3 Aug 2007): + +* Added two properties (`no_markup` and `no_entities`) to the parser + allowing HTML tags and entities to be disabled. + +* Fix for a problem introduced in 1.0.1g where posting comments in + WordPress would trigger PHP warnings and cause some markup to be + incorrectly filtered by the kses filter in WordPress. + + +Extra 1.1.3 (3 Jul 2007): + +* Fixed a performance problem when parsing some invalid HTML as an HTML + block which was resulting in too much recusion and a segmentation fault + for long documents. + +* The markdown="" attribute now accepts unquoted values. + +* Fixed an issue where underscore-emphasis didn't work when applied on the + first or the last word of an element having the markdown="1" or + markdown="span" attribute set unless there was some surrounding whitespace. + This didn't work: + +

_Hello_ _world_

+ + Now it does produce emphasis as expected. + +* Fixed an issue preventing footnotes from working when the parser's + footnote id prefix variable (fn_id_prefix) is not empty. + +* Fixed a performance problem where the regular expression for strong + emphasis introduced in version 1.1 could sometime be long to process, + give slightly wrong results, and in some circumstances could remove + entirely the content for a whole paragraph. + +* Fixed an issue were abbreviations tags could be incorrectly added + inside URLs and title of links. + +* Placing footnote markers inside a link, resulting in two nested links, is + no longer allowed. + + +1.0.1g (3 Jul 2007): + +* Fix for PHP 5 compiled without the mbstring module. Previous fix to + calculate the length of UTF-8 strings in `detab` when `mb_strlen` is + not available was only working with PHP 4. + +* Fixed a problem with WordPress 2.x where full-content posts in RSS feeds + were not processed correctly by Markdown. + +* Now supports URLs containing literal parentheses for inline links + and images, such as: + + [WIMP](http://en.wikipedia.org/wiki/WIMP_(computing)) + + Such parentheses may be arbitrarily nested, but must be + balanced. Unbalenced parentheses are allowed however when the URL + when escaped or when the URL is enclosed in angle brakets `<>`. + +* Fixed a performance problem where the regular expression for strong + emphasis introduced in version 1.0.1d could sometime be long to process, + give slightly wrong results, and in some circumstances could remove + entirely the content for a whole paragraph. + +* Some change in version 1.0.1d made possible the incorrect nesting of + anchors within each other. This is now fixed. + +* Fixed a rare issue where certain MD5 hashes in the content could + be changed to their corresponding text. For instance, this: + + The MD5 value for "+" is "26b17225b626fb9238849fd60eabdf60". + + was incorrectly changed to this in previous versions of PHP Markdown: + +

The MD5 value for "+" is "+".

+ +* Now convert escaped characters to their numeric character + references equivalent. + + This fix an integration issue with SmartyPants and backslash escapes. + Since Markdown and SmartyPants have some escapable characters in common, + it was sometime necessary to escape them twice. Previously, two + backslashes were sometime required to prevent Markdown from "eating" the + backslash before SmartyPants sees it: + + Here are two hyphens: \\-- + + Now, only one backslash will do: + + Here are two hyphens: \-- + + +Extra 1.1.2 (7 Feb 2007) + +* Fixed an issue where headers preceded too closely by a paragraph + (with no blank line separating them) where put inside the paragraph. + +* Added the missing TextileRestricted method that was added to regular + PHP Markdown since 1.0.1d but which I forgot to add to Extra. + + +1.0.1f (7 Feb 2007): + +* Fixed an issue with WordPress where manually-entered excerpts, but + not the auto-generated ones, would contain nested paragraphs. + +* Fixed an issue introduced in 1.0.1d where headers and blockquotes + preceded too closely by a paragraph (not separated by a blank line) + where incorrectly put inside the paragraph. + +* Fixed an issue introduced in 1.0.1d in the tokenizeHTML method where + two consecutive code spans would be merged into one when together they + form a valid tag in a multiline paragraph. + +* Fixed an long-prevailing issue where blank lines in code blocks would + be doubled when the code block is in a list item. + + This was due to the list processing functions relying on artificially + doubled blank lines to correctly determine when list items should + contain block-level content. The list item processing model was thus + changed to avoid the need for double blank lines. + +* Fixed an issue with `<% asp-style %>` instructions used as inline + content where the opening `<` was encoded as `<`. + +* Fixed a parse error occuring when PHP is configured to accept + ASP-style delimiters as boundaries for PHP scripts. + +* Fixed a bug introduced in 1.0.1d where underscores in automatic links + got swapped with emphasis tags. + + +Extra 1.1.1 (28 Dec 2006) + +* Fixed a problem where whitespace at the end of the line of an atx-style + header would cause tailing `#` to appear as part of the header's content. + This was caused by a small error in the regex that handles the definition + for the id attribute in PHP Markdown Extra. + +* Fixed a problem where empty abbreviations definitions would eat the + following line as its definition. + +* Fixed an issue with calling the Markdown parser repetitivly with text + containing footnotes. The footnote hashes were not reinitialized properly. + + +1.0.1e (28 Dec 2006) + +* Added support for internationalized domain names for email addresses in + automatic link. Improved the speed at which email addresses are converted + to entities. Thanks to Milian Wolff for his optimisations. + +* Made deterministic the conversion to entities of email addresses in + automatic links. This means that a given email address will always be + encoded the same way. + +* PHP Markdown will now use its own function to calculate the length of an + UTF-8 string in `detab` when `mb_strlen` is not available instead of + giving a fatal error. + + +Extra 1.1 (1 Dec 2006) + +* Added a syntax for footnotes. + +* Added an experimental syntax to define abbreviations. + + +1.0.1d (1 Dec 2006) + +* Fixed a bug where inline images always had an empty title attribute. The + title attribute is now present only when explicitly defined. + +* Link references definitions can now have an empty title, previously if the + title was defined but left empty the link definition was ignored. This can + be useful if you want an empty title attribute in images to hide the + tooltip in Internet Explorer. + +* Made `detab` aware of UTF-8 characters. UTF-8 multi-byte sequences are now + correctly mapped to one character instead of the number of bytes. + +* Fixed a small bug with WordPress where WordPress' default filter `wpautop` + was not properly deactivated on comment text, resulting in hard line breaks + where Markdown do not prescribes them. + +* Added a `TextileRestrited` method to the textile compatibility mode. There + is no restriction however, as Markdown does not have a restricted mode at + this point. This should make PHP Markdown work again in the latest + versions of TextPattern. + +* Converted PHP Markdown to a object-oriented design. + +* Changed span and block gamut methods so that they loop over a + customizable list of methods. This makes subclassing the parser a more + interesting option for creating syntax extensions. + +* Also added a "document" gamut loop which can be used to hook document-level + methods (like for striping link definitions). + +* Changed all methods which were inserting HTML code so that they now return + a hashed representation of the code. New methods `hashSpan` and `hashBlock` + are used to hash respectivly span- and block-level generated content. This + has a couple of significant effects: + + 1. It prevents invalid nesting of Markdown-generated elements which + could occur occuring with constructs like `*something [link*][1]`. + 2. It prevents problems occuring with deeply nested lists on which + paragraphs were ill-formed. + 3. It removes the need to call `hashHTMLBlocks` twice during the the + block gamut. + + Hashes are turned back to HTML prior output. + +* Made the block-level HTML parser smarter using a specially-crafted regular + expression capable of handling nested tags. + +* Solved backtick issues in tag attributes by rewriting the HTML tokenizer to + be aware of code spans. All these lines should work correctly now: + + bar + bar + `` + +* Changed the parsing of HTML comments to match simply from `` + instead using of the more complicated SGML-style rule with paired `--`. + This is how most browsers parse comments and how XML defines them too. + +* `
` has been added to the list of block-level elements and is now + treated as an HTML block instead of being wrapped within paragraph tags. + +* Now only trim trailing newlines from code blocks, instead of trimming + all trailing whitespace characters. + +* Fixed bug where this: + + [text](http://m.com "title" ) + + wasn't working as expected, because the parser wasn't allowing for spaces + before the closing paren. + +* Filthy hack to support markdown='1' in div tags. + +* _DoAutoLinks() now supports the 'dict://' URL scheme. + +* PHP- and ASP-style processor instructions are now protected as + raw HTML blocks. + + + <% ... %> + +* Fix for escaped backticks still triggering code spans: + + There are two raw backticks here: \` and here: \`, not a code span + + +Extra 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. + + +Extra 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. + + +Extra 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 ## + + +Extra 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. + +Extra 1.0b1 (25 Jun 2005) + +* First public release of PHP Markdown Extra. + + +Copyright and License +--------------------- + +PHP Markdown & Extra +Copyright (c) 2004-2009 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/blog/wp-content/plugins/markdown/markdown.php b/blog/wp-content/plugins/markdown/markdown.php old mode 100644 new mode 100755 index dd1b9e5..ee3dddb --- a/blog/wp-content/plugins/markdown/markdown.php +++ b/blog/wp-content/plugins/markdown/markdown.php @@ -1,8 +1,8 @@ # @@ -13,6 +13,7 @@ define( 'MARKDOWN_VERSION', "1.0.1n" ); # Sat 10 Oct 2009 +define( 'MARKDOWNEXTRA_VERSION', "1.2.4" ); # Sat 10 Oct 2009 # @@ -25,6 +26,14 @@ define( 'MARKDOWN_VERSION', "1.0.1n" ); # Sat 10 Oct 2009 # Define the width of a tab for code blocks. @define( 'MARKDOWN_TAB_WIDTH', 4 ); +# Optional title attribute for footnote links and backlinks. +@define( 'MARKDOWN_FN_LINK_TITLE', "" ); +@define( 'MARKDOWN_FN_BACKLINK_TITLE', "" ); + +# Optional class attribute for footnote links and backlinks. +@define( 'MARKDOWN_FN_LINK_CLASS', "" ); +@define( 'MARKDOWN_FN_BACKLINK_CLASS', "" ); + # # WordPress settings: @@ -38,7 +47,7 @@ define( 'MARKDOWN_VERSION', "1.0.1n" ); # Sat 10 Oct 2009 ### Standard Function Interface ### -@define( 'MARKDOWN_PARSER_CLASS', 'Markdown_Parser' ); +@define( 'MARKDOWN_PARSER_CLASS', 'MarkdownExtra_Parser' ); function Markdown($text) { # @@ -59,10 +68,10 @@ function Markdown($text) { ### WordPress Plugin Interface ### /* -Plugin Name: Markdown +Plugin Name: Markdown Extra Plugin URI: http://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.1n +Version: 1.2.4 Author: Michel Fortin Author URI: http://michelf.com/ */ @@ -79,9 +88,9 @@ if (isset($wp_version)) { remove_filter('the_content', 'wpautop'); remove_filter('the_content_rss', 'wpautop'); remove_filter('the_excerpt', 'wpautop'); - add_filter('the_content', 'Markdown', 6); - add_filter('the_content_rss', 'Markdown', 6); - add_filter('get_the_excerpt', 'Markdown', 6); + add_filter('the_content', 'mdwp_MarkdownPost', 6); + add_filter('the_content_rss', 'mdwp_MarkdownPost', 6); + add_filter('get_the_excerpt', 'mdwp_MarkdownPost', 6); add_filter('get_the_excerpt', 'trim', 7); add_filter('the_excerpt', 'mdwp_add_p'); add_filter('the_excerpt_rss', 'mdwp_strip_p'); @@ -92,6 +101,21 @@ if (isset($wp_version)) { add_filter('get_the_excerpt', 'balanceTags', 9); } + # Add a footnote id prefix to posts when inside a loop. + function mdwp_MarkdownPost($text) { + static $parser; + if (!$parser) { + $parser_class = MARKDOWN_PARSER_CLASS; + $parser = new $parser_class; + } + if (is_single() || is_page() || is_feed()) { + $parser->fn_id_prefix = ""; + } else { + $parser->fn_id_prefix = get_the_ID() . "."; + } + return $parser->transform($text); + } + # Comments # - Remove WordPress paragraph generator. # - Remove WordPress auto-link generator. @@ -140,15 +164,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' => 'BSD-like', - '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...', + ); } @@ -1645,16 +1669,1192 @@ class Markdown_Parser { } + +# +# Markdown Extra Parser Class +# + +class MarkdownExtra_Parser extends Markdown_Parser { + + # Prefix for footnote ids. + var $fn_id_prefix = ""; + + # Optional title attribute for footnote links and backlinks. + var $fn_link_title = MARKDOWN_FN_LINK_TITLE; + var $fn_backlink_title = MARKDOWN_FN_BACKLINK_TITLE; + + # Optional class attribute for footnote links and backlinks. + var $fn_link_class = MARKDOWN_FN_LINK_CLASS; + var $fn_backlink_class = MARKDOWN_FN_BACKLINK_CLASS; + + # Predefined abbreviations. + var $predef_abbr = array(); + + + function MarkdownExtra_Parser() { + # + # Constructor function. Initialize the parser object. + # + # Add extra escapable characters before parent constructor + # initialize the table. + $this->escape_chars .= ':|'; + + # Insert extra document, block, and span transformations. + # Parent constructor will do the sorting. + $this->document_gamut += array( + "doFencedCodeBlocks" => 5, + "stripFootnotes" => 15, + "stripAbbreviations" => 25, + "appendFootnotes" => 50, + ); + $this->block_gamut += array( + "doFencedCodeBlocks" => 5, + "doTables" => 15, + "doDefLists" => 45, + ); + $this->span_gamut += array( + "doFootnotes" => 5, + "doAbbreviations" => 70, + ); + + parent::Markdown_Parser(); + } + + + # Extra variables used during extra transformations. + var $footnotes = array(); + var $footnotes_ordered = array(); + var $abbr_desciptions = array(); + var $abbr_word_re = ''; + + # Give the current footnote number. + var $footnote_counter = 1; + + + function setup() { + # + # Setting up Extra-specific variables. + # + parent::setup(); + + $this->footnotes = array(); + $this->footnotes_ordered = array(); + $this->abbr_desciptions = array(); + $this->abbr_word_re = ''; + $this->footnote_counter = 1; + + foreach ($this->predef_abbr as $abbr_word => $abbr_desc) { + if ($this->abbr_word_re) + $this->abbr_word_re .= '|'; + $this->abbr_word_re .= preg_quote($abbr_word); + $this->abbr_desciptions[$abbr_word] = trim($abbr_desc); + } + } + + function teardown() { + # + # Clearing Extra-specific variables. + # + $this->footnotes = array(); + $this->footnotes_ordered = array(); + $this->abbr_desciptions = array(); + $this->abbr_word_re = ''; + + parent::teardown(); + } + + + ### HTML Block Parser ### + + # Tags that are always treated as block tags: + var $block_tags_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|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_re = 'script|noscript|math|ins|del'; + + # Tags where markdown="1" default to span mode: + var $contain_span_tags_re = 'p|h[1-6]|li|dd|dt|td|th|legend|address'; + + # Tags which must not have their contents modified, no matter where + # they appear: + var $clean_tags_re = 'script|math'; + + # Tags that do not need to be closed. + var $auto_close_tags_re = '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_re = '', $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_re 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_before_re = '/(?:^\n?|\n\n)*$/'; + $newline_after_re = + '{ + ^ # Start of text following the tag. + (?>[ ]*)? # Optional comment. + [ ]*\n # Must be followed by newline. + }xs'; + + # Regex to match any tag. + $block_tag_re = + '{ + ( # $2: Capture hole tag. + # Tag name. + '.$this->block_tags_re.' | + '.$this->context_block_tags_re.' | + '.$this->clean_tags_re.' | + (?!\s)'.$enclosing_tag_re.' + ) + (?: + (?=[\s"\'/a-zA-Z0-9]) # Allowed characters after tag name. + (?> + ".*?" | # Double quotes (can contain `>`) + \'.*?\' | # Single quotes (can contain `>`) + .+? # Anything but quotes and `>`. + )*? + )? + > # End of tag. + | + # HTML Comment + | + <\?.*?\?> | <%.*?%> # Processing instruction + | + # CData Block + | + # Code span marker + `+ + '. ( !$span ? ' # If not in span. + | + # Indented code block + (?: ^[ ]*\n | ^ | \n[ ]*\n ) + [ ]{'.($indent+4).'}[^\n]* \n + (?> + (?: [ ]{'.($indent+4).'}[^\n]* | [ ]* ) \n + )* + | + # Fenced code block marker + (?> ^ | \n ) + [ ]{'.($indent).'}~~~+[ ]*\n + ' : '' ). ' # End (if not is span). + ) + }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_re, $text, 2, + PREG_SPLIT_DELIM_CAPTURE); + + # If in Markdown span mode, add a empty-string span-level hash + # after each newline to prevent triggering any block element. + if ($span) { + $void = $this->hashPart("", ':'); + $newline = "$void\n"; + $parts[0] = $void . str_replace("\n", $newline, $parts[0]) . $void; + } + + $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. + $tag_re = preg_quote($tag); # For use in a regular expression. + + # + # Check for: Code span marker + # + if ($tag{0} == "`") { + # Find corresponding end marker. + $tag_re = preg_quote($tag); + if (preg_match('{^(?>.+?|\n(?!\n))*?(?.*\n)+?'.$tag_re.' *\n}', $text, + $matches)) + { + # End marker found: pass text unchanged until marker. + $parsed .= $tag . $matches[0]; + $text = substr($text, strlen($matches[0])); + } + else { + # No end marker: just skip it. + $parsed .= $tag; + } + } + # + # Check for: Opening Block level tag or + # Opening Context 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_re.')\b}', $tag) || + ( preg_match('{^<(?:'.$this->context_block_tags_re.')\b}', $tag) && + preg_match($newline_before_re, $parsed) && + preg_match($newline_after_re, $text) ) + ) + { + # Need to parse tag and following text using the HTML parser. + list($block_text, $text) = + $this->_hashHTMLBlocks_inHTML($tag . $text, "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_re.')\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, "hashClean", false); + + $parsed .= $block_text; + } + # + # Check for: Tag with same name as enclosing tag. + # + else if ($enclosing_tag_re !== '' && + # 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_re = ' + { + \s* # Eat whitespace before the `markdown` attribute + markdown + \s*=\s* + (?> + (["\']) # $1: quote delimiter + (.*?) # $2: attribute value + \1 # matching delimiter + | + ([^\s>]*) # $3: unquoted attribute value + ) + () # $4: make $3 always defined (avoid warnings) + }xs'; + + # Regex to match any tag. + $tag_re = '{ + ( # $2: Capture hole tag. + + ".*?" | # Double quotes (can contain `>`) + \'.*?\' | # 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. + # (This pattern makes $base_tag_name_re safe without quoting.) + # + if (preg_match('/^<([\w:$]*)\b/', $text, $matches)) + $base_tag_name_re = $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_re, $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_re.')\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_m[2] . $attr_m[3]; + $span_mode = $this->mode == 'span' || $this->mode != 'block' && + preg_match('{^<(?:'.$this->contain_span_tags_re.')\b}', $tag); + + # Calculate indent before tag. + if (preg_match('/(?:^|\n)( *?)(?! ).*?$/', $block_text, $matches)) { + $strlen = $this->utf8_strlen; + $indent = $strlen($matches[1], 'UTF-8'); + } else { + $indent = 0; + } + + # End preceding block with this tag. + $block_text .= $tag; + $parsed .= $this->$hash_method($block_text); + + # Get enclosing tag name for the ParseMarkdown function. + # (This pattern makes $tag_name_re safe without quoting.) + preg_match('/^<([\w:$]*)\b/', $tag, $matches); + $tag_name_re = $matches[1]; + + # Parse the content using the HTML-in-Markdown parser. + list ($block_text, $text) + = $this->_hashHTMLBlocks_inMarkdown($text, $indent, + $tag_name_re, $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 hashClean($text) { + # + # Called whenever a tag must be hashed when a function insert a "clean" tag + # in $text, it pass through this function and is automaticaly escaped, + # blocking invalid nested overlap. + # + return $this->hashPart($text, 'C'); + } + + + function doHeaders($text) { + # + # Redefined to add id attribute support. + # + # Setext-style headers: + # Header 1 {#header1} + # ======== + # + # Header 2 {#header2} + # -------- + # + $text = preg_replace_callback( + '{ + (^.+?) # $1: Header text + (?:[ ]+\{\#([-_:a-zA-Z0-9]+)\})? # $2: Id attribute + [ ]*\n(=+|-+)[ ]*\n+ # $3: Header footer + }mx', + array(&$this, '_doHeaders_callback_setext'), $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 + [ ]* + (.+?) # $2 = Header text + [ ]* + \#* # 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($matches) { + if ($matches[3] == '-' && preg_match('{^- }', $matches[1])) + return $matches[0]; + $level = $matches[3]{0} == '=' ? 1 : 2; + $attr = $this->_doHeaders_attr($id =& $matches[2]); + $block = "".$this->runSpanGamut($matches[1]).""; + return "\n" . $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 "\n" . $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] = ''; + } + + # Parsing span elements, including code spans, character escapes, + # and inline HTML tags, so that pipes inside those gets ignored. + $head = $this->parseSpan($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) { + # Parsing span elements, including code spans, character escapes, + # and inline HTML tags, so that pipes inside those gets ignored. + $row = $this->parseSpan($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"; + } + + + 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_re = '(?> + ( # $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('{ + (?>\A\n?|(?<=\n\n)) + '.$whole_list_re.' + }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('{ + (?>\A\n?|\n\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 + ( # marker space = $2 + [ ]{0,'.$less_than_tab.'} # whitespace before colon + [:][ ]+ # definition mark (colon) + ) + ((?s:.+?)) # definition text = $3 + (?= \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]; + $marker_space = $matches[2]; + $def = $matches[3]; + + if ($leading_line || preg_match('/\n{2,}/', $def)) { + # Replace marker with the appropriate whitespace indentation + $def = str_repeat(' ', strlen($marker_space)) . $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 doFencedCodeBlocks($text) { + # + # Adding the fenced code block syntax to regular Markdown: + # + # ~~~ + # Code block + # ~~~ + # + $less_than_tab = $this->tab_width; + + $text = preg_replace_callback('{ + (?:\n|\A) + # 1: Opening marker + ( + ~{3,} # Marker: three tilde or more. + ) + [ ]* \n # Whitespace and newline following marker. + + # 2: Content + ( + (?> + (?!\1 [ ]* \n) # Not a closing marker. + .*\n+ + )+ + ) + + # Closing marker. + \1 [ ]* \n + }xm', + array(&$this, '_doFencedCodeBlocks_callback'), $text); + + return $text; + } + function _doFencedCodeBlocks_callback($matches) { + $codeblock = $matches[2]; + $codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES); + $codeblock = preg_replace_callback('/^\n+/', + array(&$this, '_doFencedCodeBlocks_newlines'), $codeblock); + $codeblock = "
$codeblock
"; + return "\n\n".$this->hashBlock($codeblock)."\n\n"; + } + function _doFencedCodeBlocks_newlines($matches) { + return str_repeat("empty_element_suffix", + strlen($matches[0])); + } + + + # + # Redefining emphasis markers so that emphasis by underscore does not + # work in the middle of a word. + # + var $em_relist = array( + '' => '(?:(? '(?<=\S|^)(? '(?<=\S|^)(? '(?:(? '(?<=\S|^)(? '(?<=\S|^)(? '(?:(? '(?<=\S|^)(? '(?<=\S|^)(? tags + # + # Strip leading and trailing lines: + $text = preg_replace('/\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. + # Clean tag hashes & block tag hashes are left alone. + $is_p = !preg_match('/^B\x1A[0-9]+B|^C\x1A[0-9]+C$/', $value); + + 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->unhash($text); + + return $text; + } + + + ### Footnotes + + function stripFootnotes($text) { + # + # Strips link definitions from text, stores the URLs and titles in + # hash references. + # + $less_than_tab = $this->tab_width - 1; + + # Link defs are in the form: [^id]: url "optional title" + $text = preg_replace_callback('{ + ^[ ]{0,'.$less_than_tab.'}\[\^(.+?)\][ ]?: # note_id = $1 + [ ]* + \n? # maybe *one* newline + ( # text = $2 (no blank lines allowed) + (?: + .+ # actual text + | + \n # newlines but + (?!\[\^.+?\]:\s)# negative lookahead for footnote marker. + (?!\n+[ ]{0,3}\S)# ensure line is not blank and followed + # by non-indented content + )* + ) + }xm', + array(&$this, '_stripFootnotes_callback'), + $text); + return $text; + } + function _stripFootnotes_callback($matches) { + $note_id = $this->fn_id_prefix . $matches[1]; + $this->footnotes[$note_id] = $this->outdent($matches[2]); + return ''; # String that will replace the block + } + + + function doFootnotes($text) { + # + # Replace footnote references in $text [^id] with a special text-token + # which will be replaced by the actual footnote marker in appendFootnotes. + # + if (!$this->in_anchor) { + $text = preg_replace('{\[\^(.+?)\]}', "F\x1Afn:\\1\x1A:", $text); + } + return $text; + } + + + function appendFootnotes($text) { + # + # Append footnote list to text. + # + $text = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}', + array(&$this, '_appendFootnotes_callback'), $text); + + if (!empty($this->footnotes_ordered)) { + $text .= "\n\n"; + $text .= "
\n"; + $text .= "empty_element_suffix ."\n"; + $text .= "
    \n\n"; + + $attr = " rev=\"footnote\""; + if ($this->fn_backlink_class != "") { + $class = $this->fn_backlink_class; + $class = $this->encodeAttribute($class); + $attr .= " class=\"$class\""; + } + if ($this->fn_backlink_title != "") { + $title = $this->fn_backlink_title; + $title = $this->encodeAttribute($title); + $attr .= " title=\"$title\""; + } + $num = 0; + + while (!empty($this->footnotes_ordered)) { + $footnote = reset($this->footnotes_ordered); + $note_id = key($this->footnotes_ordered); + unset($this->footnotes_ordered[$note_id]); + + $footnote .= "\n"; # Need to append newline before parsing. + $footnote = $this->runBlockGamut("$footnote\n"); + $footnote = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}', + array(&$this, '_appendFootnotes_callback'), $footnote); + + $attr = str_replace("%%", ++$num, $attr); + $note_id = $this->encodeAttribute($note_id); + + # Add backlink to last paragraph; create new paragraph if needed. + $backlink = ""; + if (preg_match('{

    $}', $footnote)) { + $footnote = substr($footnote, 0, -4) . " $backlink

    "; + } else { + $footnote .= "\n\n

    $backlink

    "; + } + + $text .= "
  1. \n"; + $text .= $footnote . "\n"; + $text .= "
  2. \n\n"; + } + + $text .= "
\n"; + $text .= "
"; + } + return $text; + } + function _appendFootnotes_callback($matches) { + $node_id = $this->fn_id_prefix . $matches[1]; + + # Create footnote marker only if it has a corresponding footnote *and* + # the footnote hasn't been used by another marker. + if (isset($this->footnotes[$node_id])) { + # Transfert footnote content to the ordered list. + $this->footnotes_ordered[$node_id] = $this->footnotes[$node_id]; + unset($this->footnotes[$node_id]); + + $num = $this->footnote_counter++; + $attr = " rel=\"footnote\""; + if ($this->fn_link_class != "") { + $class = $this->fn_link_class; + $class = $this->encodeAttribute($class); + $attr .= " class=\"$class\""; + } + if ($this->fn_link_title != "") { + $title = $this->fn_link_title; + $title = $this->encodeAttribute($title); + $attr .= " title=\"$title\""; + } + + $attr = str_replace("%%", $num, $attr); + $node_id = $this->encodeAttribute($node_id); + + return + "". + "$num". + ""; + } + + return "[^".$matches[1]."]"; + } + + + ### Abbreviations ### + + function stripAbbreviations($text) { + # + # Strips abbreviations from text, stores titles in hash references. + # + $less_than_tab = $this->tab_width - 1; + + # Link defs are in the form: [id]*: url "optional title" + $text = preg_replace_callback('{ + ^[ ]{0,'.$less_than_tab.'}\*\[(.+?)\][ ]?: # abbr_id = $1 + (.*) # text = $2 (no blank lines allowed) + }xm', + array(&$this, '_stripAbbreviations_callback'), + $text); + return $text; + } + function _stripAbbreviations_callback($matches) { + $abbr_word = $matches[1]; + $abbr_desc = $matches[2]; + if ($this->abbr_word_re) + $this->abbr_word_re .= '|'; + $this->abbr_word_re .= preg_quote($abbr_word); + $this->abbr_desciptions[$abbr_word] = trim($abbr_desc); + return ''; # String that will replace the block + } + + + function doAbbreviations($text) { + # + # Find defined abbreviations in text and wrap them in elements. + # + if ($this->abbr_word_re) { + // cannot use the /x modifier because abbr_word_re may + // contain significant spaces: + $text = preg_replace_callback('{'. + '(?abbr_word_re.')'. + '(?![\w\x1A])'. + '}', + array(&$this, '_doAbbreviations_callback'), $text); + } + return $text; + } + function _doAbbreviations_callback($matches) { + $abbr = $matches[0]; + if (isset($this->abbr_desciptions[$abbr])) { + $desc = $this->abbr_desciptions[$abbr]; + if (empty($desc)) { + return $this->hashPart("$abbr"); + } else { + $desc = $this->encodeAttribute($desc); + return $this->hashPart("$abbr"); + } + } else { + return $matches[0]; + } + } + +} + + /* -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 @@ -1691,12 +2891,12 @@ See the readme file for detailed release notes for this version. Copyright and License --------------------- -PHP Markdown +PHP Markdown & Extra Copyright (c) 2004-2009 Michel Fortin All rights reserved. -Based on Markdown +Based on Markdown Copyright (c) 2003-2006 John Gruber All rights reserved.