Making WordPress.org

Changeset 2501


Ignore:
Timestamp:
02/15/2016 06:28:02 AM (10 years ago)
Author:
obenland
Message:

W.org Plugins: Code reformatting.

  • Splitting out classes in their own files.
  • Let the automated code formatter run over the plugin.

It should break too many things.

See #1584.

Location:
sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory
Files:
3 added
4 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/plugin-directory.php

    r2499 r2501  
    11<?php
    2 /*
    3  * Plugin Name: Plugin Repository
     2/**
     3 * Plugin Name: Plugin Directory
    44 * Plugin URI: http://wordpress.org/plugins/
    55 * Description: Transforms a WordPress site in The Official Plugin Directory.
    66 * Version: 0.1
    7  * Author: wordpressdotorg
    8  * Author URI: http://wordpress.org/
     7 * Author: the WordPress team
     8 * Author URI: https://wordpress.org/
    99 * Text Domain: wporg-plugins
    1010 * License: GPLv2
    1111 * License URI: http://opensource.org/licenses/gpl-2.0.php
     12 *
     13 * @package WPorg_Plugin_Directory
    1214 */
    1315
    14 class Plugin_Directory {
     16include_once( 'class-wporg-plugin-directory.php' );
     17include_once( 'class-wporg-plugin-directory-template.php' );
     18include_once( 'class-wporg-plugin-directory-tools.php' );
    1519
    16     function __construct() {
    17         register_activation_hook( __FILE__, array( $this, 'activate' ) );
    18         register_deactivation_hook( __FILE__, array( $this, 'deactivate' ) );
    19 
    20         add_action( 'init', array( $this, 'init' ) );
    21         add_filter( 'post_type_link', array( $this, 'package_link' ), 10, 2 );
    22         add_filter( 'pre_insert_term', array( $this, 'pre_insert_term_prevent' ) );
    23         add_action( 'pre_get_posts', array( $this, 'use_plugins_in_query' ) );
    24         add_filter( 'the_content', array( $this, 'filter_post_content_to_correct_page' ), 1 );
    25     }
    26 
    27     function activate() {
    28         global $wp_rewrite;
    29 
    30         // Setup the environment
    31         $this->init();
    32 
    33         // %postname% is required
    34         $wp_rewrite->set_permalink_structure( '/%postname%/' );
    35 
    36         // /tags/%slug% is required for tags
    37         $wp_rewrite->set_tag_base( '/tags' );
    38 
    39         // We require the WordPress.org Ratings plugin also be active
    40         if ( ! is_plugin_active( 'wporg-ratings/wporg-ratings.php' ) ) {
    41             activate_plugin( 'wporg-ratings/wporg-ratings.php' );
    42         }
    43    
    44         // Enable the WordPress.org Theme Repo Theme
    45         foreach ( wp_get_themes() as $theme ) {
    46             if ( $theme->get( 'Name' ) === 'WordPress.org Plugins' ) {
    47                 switch_theme( $theme->get_stylesheet() );
    48                 break;
    49             }
    50         }
    51    
    52         flush_rewrite_rules();
    53    
    54         do_action( 'wporg_plugins_activation' );
    55     }
    56 
    57     function deactivate() {
    58         flush_rewrite_rules();
    59    
    60         do_action( 'wporg_plugins_deactivation' );
    61     }
    62 
    63 
    64     function init() {
    65         load_plugin_textdomain( 'wporg-plugins' );
    66 
    67         register_post_type( 'plugin', array(
    68             'labels'      => array(
    69                 'name'               => __( 'Plugins', 'wporg-plugins' ),
    70                 'singular_name'      => __( 'Plugin', 'wporg-plugins' ),
    71                 'add_new'            => __( 'Add New', 'wporg-plugins' ),
    72                 'add_new_item'       => __( 'Add New Plugin', 'wporg-plugins' ),
    73                 'edit_item'          => __( 'Edit Plugin', 'wporg-plugins' ),
    74                 'new_item'           => __( 'New Plugin', 'wporg-plugins' ),
    75                 'view_item'          => __( 'View Plugin', 'wporg-plugins' ),
    76                 'search_items'       => __( 'Search Plugins', 'wporg-plugins' ),
    77                 'not_found'          => __( 'No plugins found', 'wporg-plugins' ),
    78                 'not_found_in_trash' => __( 'No plugins found in Trash', 'wporg-plugins' ),
    79                 'menu_name'          => __( 'My Plugins', 'wporg-plugins' ),
    80             ),
    81             'description' => __( 'A package', 'wporg-plugins' ),
    82             'supports'    => array( 'title', 'editor', 'excerpt', 'custom-fields' ),
    83             'taxonomies'  => array( 'post_tag', 'category' ),
    84             'public'      => true,
    85             'show_ui'     => true,
    86             'has_archive' => true,
    87             'rewrite'     => false,
    88             'menu_icon'   => 'dashicons-admin-plugins',
    89         ) );
    90 
    91         register_post_status( 'pending', array(
    92             'label' => _x( 'Pending', 'plugin status', 'wporg-plugins' ),
    93             'public' => false,
    94             'show_in_admin_status_list' => true,
    95             'label_count' => _n_noop( 'Pending <span class="count">(%s)</span>', 'Pending <span class="count">(%s)</span>', 'wporg-plugins' ),
    96         ) );
    97         register_post_status( 'disabled', array(
    98             'label' => _x( 'Disabled', 'plugin status', 'wporg-plugins' ),
    99             'public' => false,
    100             'show_in_admin_status_list' => true,
    101             'label_count' => _n_noop( 'Disabled <span class="count">(%s)</span>', 'Disabled <span class="count">(%s)</span>', 'wporg-plugins' ),
    102         ) );
    103         register_post_status( 'closed', array(
    104             'label' => _x( 'Closed', 'plugin status', 'wporg-plugins' ),
    105             'public' => false,
    106             'show_in_admin_status_list' => true,
    107             'label_count' => _n_noop( 'Closed <span class="count">(%s)</span>', 'Closed <span class="count">(%s)</span>', 'wporg-plugins' ),
    108         ) );
    109    
    110         // Add the browse/* views
    111         add_rewrite_tag( '%browse%', '(featured|popular|beta|new|favorites)' );
    112         add_permastruct( 'browse', 'browse/%browse%' );
    113 
    114         add_rewrite_endpoint( 'installation', EP_PERMALINK );
    115         add_rewrite_endpoint( 'faq',          EP_PERMALINK );
    116         add_rewrite_endpoint( 'screenshots',  EP_PERMALINK );
    117         add_rewrite_endpoint( 'changelog',    EP_PERMALINK );
    118         add_rewrite_endpoint( 'stats',        EP_PERMALINK );
    119         add_rewrite_endpoint( 'developers',   EP_PERMALINK );
    120         add_rewrite_endpoint( 'other_notes',  EP_PERMALINK );
    121     }
    122 
    123     /**
    124      * Filter the permalink for the Packages to be /post_name/
    125      *
    126      * @param string $link The generated permalink
    127      * @param string $post The package object
    128      * @return string
    129      */
    130     function package_link( $link, $post ) {
    131         if ( 'plugin' != $post->post_type ) {
    132             return $link;
    133         }
    134    
    135         return trailingslashit( home_url( $post->post_name ) );
    136     }
    137 
    138     /**
    139      * Checks if ther current users is a super admin before allowing terms to be added.
    140      *
    141      * @param string           $term The term to add or update.
    142      * @return string|WP_Error The term to add or update or WP_Error on failure.
    143      */
    144     function pre_insert_term_prevent( $term ) {
    145         if ( ! is_super_admin() ) {
    146             $term = new WP_Error( 'not-allowed', __( 'You are not allowed to add terms.', 'wporg-plugins' ) );
    147         }
    148    
    149         return $term;
    150     }
    151 
    152     function use_plugins_in_query( $wp_query ) {
    153         if ( ! $wp_query->is_main_query() ) {
    154             return;
    155         }
    156 
    157         if ( empty( $wp_query->query_vars['pagename'] ) &&
    158             ( empty( $wp_query->query_vars['post_type'] ) || 'posts' == $wp_query->query_vars['post_type'] ) ) {
    159             $wp_query->query_vars['post_type'] = array( 'plugin' );
    160         }
    161 
    162         if ( empty( $wp_query->query ) ) {
    163             $wp_query->query_vars['browse'] = 'featured';
    164         }
    165 
    166         switch ( get_query_var( 'browse' ) ) {
    167             case 'beta':
    168                 $wp_query->query_vars['category_name'] = 'beta';
    169                 break;
    170    
    171             case 'featured':
    172                 $wp_query->query_vars['category_name'] = 'featured';
    173                 break;
    174    
    175             case 'favorites':
    176                 break;
    177    
    178             case 'popular':
    179                 break;
    180         }
    181 
    182         // Re-route the Endpoints to the `content_page` query var.
    183         if ( !empty( $wp_query->query['name'] ) ) {
    184             foreach ( array( 'installation', 'faq', 'screenshots', 'changelog', 'stats', 'developers', 'other_notes' ) as $plugin_field ) {
    185                 if ( isset( $wp_query->query[ $plugin_field ] ) ) {
    186                     $wp_query->query['content_page'] = $wp_query->query_vars['content_page'] = $plugin_field;
    187                     unset( $wp_query->query[ $plugin_field ], $wp_query->query_vars[ $plugin_field ] );
    188                 }
    189             }
    190         }
    191     }
    192 
    193     function filter_post_content_to_correct_page( $content ) {
    194         global $content_pages;
    195 
    196         $post = get_post();
    197         if ( 'plugin' != $post->post_type ) {
    198             return $content;
    199         }
    200 
    201         $page = get_query_var( 'content_page' );
    202         $content_pages = $this->split_post_content_into_pages( $content );
    203 
    204         if ( ! isset( $content_pages[ $page ] ) ) {
    205             $page = 'description';
    206         }
    207 
    208         return $content_pages[ $page ];
    209     }
    210 
    211     function split_post_content_into_pages( $content ) {
    212         $content_pages = array(
    213             'stats' => '[wporg-plugins-stats]',
    214             'developers' => '[wporg-plugins-developer]',
    215         );
    216         $_pages = preg_split( "#<!--section=(.+?)-->#", $content, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
    217         for ( $i = 0; $i < count( $_pages ); $i += 2 ) {
    218             // Don't overwrite existing tabs.
    219             if ( ! isset( $content_pages[ $_pages[ $i ] ] ) ) {
    220                 $content_pages[ $_pages[ $i ] ] = $_pages[ $i + 1 ];
    221             }
    222         }
    223 
    224         return $content_pages;
    225     }
    226 
    227 }
    228 new Plugin_Directory();
    229 
    230 // Various functions used by other processes, will make sense to move to specific classses.
    231 class Plugin_Directory_Tools {
    232     static function get_readme_data( $readme ) {
    233         // Uses https://github.com/rmccue/WordPress-Readme-Parser (with modifications)
    234         include_once __DIR__ . '/readme-parser/markdown.php';
    235         include_once __DIR__ . '/readme-parser/compat.php';
    236 
    237         $data = (object) _WordPress_org_Readme::parse_readme( $readme );
    238 
    239         unset( $data->sections['screenshots'] ); // Useless
    240 
    241         // sanitize contributors.
    242         foreach ( $data->contributors as $i => $name ) {
    243             if ( get_user_by( 'login', $name ) ) {
    244                 continue;
    245             } elseif ( false !== ( $user = get_user_by( 'slug', $name ) ) ) {
    246                 $data->contributors[] = $user->user_login;
    247                 unset( $data->contributors[ $i ] );
    248             } else {
    249                 unset( $data->contributors[ $i ] );
    250             }
    251         }
    252 
    253         return $data;
    254     }
    255 }
    256 
    257 // Various helpers to retrieve data not stored within WordPress
    258 class Plugin_Directory_Template_Helpers {
    259     static function get_active_installs_count( $plugin_slug ) {
    260         global $wpdb;
    261    
    262         $count = wp_cache_get( $plugin_slug, 'plugin_active_installs' );
    263         if ( false === $count ) {
    264             $count = (int) $wpdb->get_var( $wpdb->prepare(
    265                 "SELECT count FROM rev2_daily_stat_summary WHERE type = 'plugin' AND type_name = %s AND stat = 'active_installs' LIMIT 1",
    266                 $plugin_slug
    267             ) );
    268             wp_cache_add( $plugin_slug, $count, 'plugin_active_installs', 1200 );
    269         }
    270    
    271         if ( $count < 10 ) {
    272             return 0;
    273         }
    274    
    275         if ( $count >= 1000000 ) {
    276             return 1000000;
    277         }
    278    
    279         return strval( $count )[0] * pow( 10, floor( log10( $count ) ) );
    280     }
    281 
    282     static function get_total_downloads() {
    283         global $wpdb;
    284 
    285         $count = wp_cache_get( 'plugin_download_count', 'plugin_download_count' );
    286         if ( false === $count ) {
    287             $count = (int) $wpdb->get_var( "SELECT SUM(downloads) FROM `plugin_2_stats`" );
    288             wp_cache_add( 'plugin_download_count', $count, 'plugin_download_count', DAY_IN_SECONDS );
    289         }
    290 
    291         return $count;
    292     }
    293 
    294     static function get_plugin_sections() {
    295         $plugin_slug  = get_post()->post_name;
    296         $raw_sections = get_post_meta( get_the_ID(), 'sections', true );
    297         $raw_sections = array_unique( array_merge( $raw_sections, array( 'description', 'stats', 'support', 'reviews', 'developers' ) ) );
    298    
    299         $sections = array();
    300         foreach ( $raw_sections as $section_slug ) {
    301             $url = get_permalink();
    302             switch ( $section_slug ) {
    303                 case 'description':
    304                     $title = _x( 'Description', 'plugin tab title', 'wporg-plugins' );
    305                     break;
    306                 case 'installation':
    307                     $title = _x( 'Installation', 'plugin tab title', 'wporg-plugins' );
    308                     $url = trailingslashit( $url ) . '/' . $section_slug . '/';
    309                     break;
    310                 case 'faq':
    311                     $title = _x( 'FAQ', 'plugin tab title', 'wporg-plugins' );
    312                     $url = trailingslashit( $url ) . '/' . $section_slug . '/';
    313                     break;
    314                 case 'screenshots':
    315                     $title = _x( 'Screenshots', 'plugin tab title', 'wporg-plugins' );
    316                     $url = trailingslashit( $url ) . '/' . $section_slug . '/';
    317                     break;
    318                 case 'changelog':
    319                     $title = _x( 'Changelog', 'plugin tab title', 'wporg-plugins' );
    320                     $url = trailingslashit( $url ) . '/' . $section_slug . '/';
    321                     break;
    322                 case 'stats':
    323                     $title = _x( 'Stats', 'plugin tab title', 'wporg-plugins' );
    324                     $url = trailingslashit( $url ) . '/' . $section_slug . '/';
    325                     break;
    326                 case 'support':
    327                     $title = _x( 'Support', 'plugin tab title', 'wporg-plugins' );
    328                     $url = 'https://wordpress.org/support/plugin/' . $plugin_slug;
    329                     break;
    330                 case 'reviews':
    331                     $title = _x( 'Reviews', 'plugin tab title', 'wporg-plugins' );
    332                     $url = 'https://wordpress.org/support/view/plugin-reviews/' . $plugin_slug;
    333                     break;
    334                 case 'developers':
    335                     $title = _x( 'Developers', 'plugin tab title', 'wporg-plugins' );
    336                     $url = trailingslashit( $url ) . '/' . $section_slug . '/';
    337                     break;
    338             }
    339             $sections[] = array(
    340                 'slug'  => $section_slug,
    341                 'url'   => $url,
    342                 'title' => $title,
    343             );
    344         }
    345         return $sections;
    346     }
    347 }
    348    
     20$wporg_plugin_directory = new WPorg_Plugin_Directory();
     21register_activation_hook( __FILE__, array( $wporg_plugin_directory, 'activate' ) );
     22register_deactivation_hook( __FILE__, array( $wporg_plugin_directory, 'deactivate' ) );
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/readme-parser/ReadmeParser.php

    r2499 r2501  
    11<?php
    22/**
    3  * Custom readme parser
     3 * Custom readme parser.
    44 *
    55 * Based on Automattic_Readme from http://code.google.com/p/wordpress-plugin-readme-parser/
     
    1010 * @todo Create validator for this based on http://code.google.com/p/wordpress-plugin-readme-parser/source/browse/trunk/validator.php
    1111 */
     12
     13/**
     14 * Class Baikonur_ReadmeParser
     15 */
    1216class Baikonur_ReadmeParser {
    13 
    14     public static function parse_readme($file) {
    15         $contents = file($file);
    16         return self::parse_readme_contents($contents);
    17     }
    18 
    19     public static function parse_readme_contents($contents) {
    20         if (is_string($contents)) {
    21             $contents = explode("\n", $contents);
     17    public static function parse_readme( $file ) {
     18        $contents = file( $file );
     19
     20        return self::parse_readme_contents( $contents );
     21    }
     22
     23    public static function parse_readme_contents( $contents ) {
     24        if ( is_string( $contents ) ) {
     25            $contents = explode( "\n", $contents );
    2226        }
    2327
    2428        $this_class = __CLASS__;
    25         if (function_exists('get_called_class')) {
     29        if ( function_exists( 'get_called_class' ) ) {
    2630            $this_class = get_called_class();
    2731        }
    2832
    29         $contents = array_map(array($this_class, 'strip_newlines'), $contents);
     33        $contents = array_map( array( $this_class, 'strip_newlines' ), $contents );
    3034
    3135        // Strip BOM
    32         if (strpos($contents[0], "\xEF\xBB\xBF") === 0) {
    33             $contents[0] = substr($contents[0], 3);
     36        if ( strpos( $contents[0], "\xEF\xBB\xBF" ) === 0 ) {
     37            $contents[0] = substr( $contents[0], 3 );
    3438        }
    3539
     
    3741
    3842        // Defaults
    39         $data->is_excerpt = false;
    40         $data->is_truncated = false;
    41         $data->tags = array();
    42         $data->requires = '';
    43         $data->tested = '';
    44         $data->contributors = array();
    45         $data->stable_tag = '';
    46         $data->version = '';
    47         $data->donate_link = '';
     43        $data->is_excerpt        = false;
     44        $data->is_truncated      = false;
     45        $data->tags              = array();
     46        $data->requires          = '';
     47        $data->tested            = '';
     48        $data->contributors      = array();
     49        $data->stable_tag        = '';
     50        $data->version           = '';
     51        $data->donate_link       = '';
    4852        $data->short_description = '';
    49         $data->sections = array();
    50         $data->changelog = array();
    51         $data->upgrade_notice = array();
    52         $data->screenshots = array();
     53        $data->sections          = array();
     54        $data->changelog         = array();
     55        $data->upgrade_notice    = array();
     56        $data->screenshots       = array();
    5357        $data->remaining_content = array();
    5458
    55         $line = call_user_func_array(array($this_class, 'get_first_nonwhitespace'), array(&$contents));
     59        $line       = call_user_func_array( array( $this_class, 'get_first_nonwhitespace' ), array( &$contents ) );
    5660        $data->name = $line;
    57         $data->name = trim($data->name, "#= ");
     61        $data->name = trim( $data->name, "#= " );
    5862
    5963        // Parse headers
    6064        $headers = array();
    6165
    62         $line = call_user_func_array(array($this_class, 'get_first_nonwhitespace'), array(&$contents));
     66        $line = call_user_func_array( array( $this_class, 'get_first_nonwhitespace' ), array( &$contents ) );
    6367        do {
    6468            $key = $value = null;
    65             if (strpos($line, ':') === false) {
     69            if ( strpos( $line, ':' ) === false ) {
    6670                break;
    6771            }
    68             $bits = explode(':', $line, 2);
    69             list($key, $value) = $bits;
    70             $key = strtolower(str_replace(array(' ', "\t"), '_', trim($key)));
    71             if ($key === 'tags' && isset($headers['tags'])) {
    72                 $headers[$key] .= ',' . trim($value);
    73             }
    74             else {
    75                 $headers[$key] = trim($value);
    76             }
    77         }
    78         while (($line = array_shift($contents)) !== null && ($line = trim($line)) && !empty($line));
    79         array_unshift($contents, $line);
    80 
    81         if (!empty($headers['tags'])) {
    82             $data->tags = explode(',', $headers['tags']);
    83             $data->tags = array_map('trim', $data->tags);
    84         }
    85         if (!empty($headers['requires'])) {
     72            $bits = explode( ':', $line, 2 );
     73            list( $key, $value ) = $bits;
     74            $key = strtolower( str_replace( array( ' ', "\t" ), '_', trim( $key ) ) );
     75            if ( $key === 'tags' && isset( $headers['tags'] ) ) {
     76                $headers[ $key ] .= ',' . trim( $value );
     77            } else {
     78                $headers[ $key ] = trim( $value );
     79            }
     80        } while ( ( $line = array_shift( $contents ) ) !== null && ( $line = trim( $line ) ) && ! empty( $line ) );
     81        array_unshift( $contents, $line );
     82
     83        if ( ! empty( $headers['tags'] ) ) {
     84            $data->tags = explode( ',', $headers['tags'] );
     85            $data->tags = array_map( 'trim', $data->tags );
     86        }
     87        if ( ! empty( $headers['requires'] ) ) {
    8688            $data->requires = $headers['requires'];
    8789        }
    88         if (!empty($headers['requires_at_least'])) {
     90        if ( ! empty( $headers['requires_at_least'] ) ) {
    8991            $data->requires = $headers['requires_at_least'];
    9092        }
    91         if (!empty($headers['tested'])) {
     93        if ( ! empty( $headers['tested'] ) ) {
    9294            $data->tested = $headers['tested'];
    9395        }
    94         if (!empty($headers['tested_up_to'])) {
     96        if ( ! empty( $headers['tested_up_to'] ) ) {
    9597            $data->tested = $headers['tested_up_to'];
    9698        }
    97         if (!empty($headers['contributors'])) {
    98             $data->contributors = explode(',', $headers['contributors']);
    99             $data->contributors = array_map('trim', $data->contributors);
    100         }
    101         if (!empty($headers['stable_tag'])) {
     99        if ( ! empty( $headers['contributors'] ) ) {
     100            $data->contributors = explode( ',', $headers['contributors'] );
     101            $data->contributors = array_map( 'trim', $data->contributors );
     102        }
     103        if ( ! empty( $headers['stable_tag'] ) ) {
    102104            $data->stable_tag = $headers['stable_tag'];
    103105        }
    104         if (!empty($headers['donate_link'])) {
     106        if ( ! empty( $headers['donate_link'] ) ) {
    105107            $data->donate_link = $headers['donate_link'];
    106108        }
    107         if (!empty($headers['version'])) {
     109        if ( ! empty( $headers['version'] ) ) {
    108110            $data->version = $headers['version'];
    109         }
    110         else {
     111        } else {
    111112            $data->version = $data->stable_tag;
    112113        }
    113114
    114115        // Parse the short description
    115         while (($line = array_shift($contents)) !== null) {
    116             $trimmed = trim($line);
    117             if (empty($trimmed)) {
     116        while ( ( $line = array_shift( $contents ) ) !== null ) {
     117            $trimmed = trim( $line );
     118            if ( empty( $trimmed ) ) {
    118119                $data->short_description .= "\n";
    119120                continue;
    120121            }
    121             if ($trimmed[0] === '=' && isset($trimmed[1]) && $trimmed[1] === '=') {
    122                 array_unshift($contents, $line);
     122            if ( $trimmed[0] === '=' && isset( $trimmed[1] ) && $trimmed[1] === '=' ) {
     123                array_unshift( $contents, $line );
    123124                break;
    124125            }
     
    126127            $data->short_description .= $line . "\n";
    127128        }
    128         $data->short_description = trim($data->short_description);
    129 
    130         $data->is_truncated = call_user_func_array(array($this_class, 'trim_short_desc'), array(&$data->short_description));
     129        $data->short_description = trim( $data->short_description );
     130
     131        $data->is_truncated = call_user_func_array( array(
     132            $this_class,
     133            'trim_short_desc'
     134        ), array( &$data->short_description ) );
    131135
    132136        // Parse the rest of the body
    133137        $current = '';
    134         $special = array('description', 'installation', 'faq', 'frequently_asked_questions', 'screenshots', 'changelog', 'upgrade_notice');
    135 
    136         while (($line = array_shift($contents)) !== null) {
    137             $trimmed = trim($line);
    138             if (empty($trimmed)) {
     138        $special = array(
     139            'description',
     140            'installation',
     141            'faq',
     142            'frequently_asked_questions',
     143            'screenshots',
     144            'changelog',
     145            'upgrade_notice'
     146        );
     147
     148        while ( ( $line = array_shift( $contents ) ) !== null ) {
     149            $trimmed = trim( $line );
     150            if ( empty( $trimmed ) ) {
    139151                $current .= "\n";
    140152                continue;
    141153            }
    142154
    143             if ($trimmed[0] === '=' && isset($trimmed[1]) && $trimmed[1] === '=') {
    144                 if (!empty($title)) {
    145                     $data->sections[$title] = trim($current);
    146                 }
    147 
    148                 $current = '';
    149                 $real_title = trim($line, "#= \t");
    150                 $title = strtolower(str_replace(' ', '_', $real_title));
    151                 if ($title === 'faq') {
     155            if ( $trimmed[0] === '=' && isset( $trimmed[1] ) && $trimmed[1] === '=' ) {
     156                if ( ! empty( $title ) ) {
     157                    $data->sections[ $title ] = trim( $current );
     158                }
     159
     160                $current    = '';
     161                $real_title = trim( $line, "#= \t" );
     162                $title      = strtolower( str_replace( ' ', '_', $real_title ) );
     163                if ( $title === 'faq' ) {
    152164                    $title = 'frequently_asked_questions';
    153                 }
    154                 elseif ($title === 'change_log') {
     165                } elseif ( $title === 'change_log' ) {
    155166                    $title = 'changelog';
    156167                }
    157                 if (!in_array($title, $special)) {
     168                if ( ! in_array( $title, $special ) ) {
    158169                    $current .= '<h3>' . $real_title . "</h3>";
    159170                }
     
    164175        }
    165176
    166         if (!empty($title)) {
    167             $data->sections[$title] = trim($current);
    168         }
    169         $title = null;
     177        if ( ! empty( $title ) ) {
     178            $data->sections[ $title ] = trim( $current );
     179        }
     180        $title   = null;
    170181        $current = null;
    171182
    172         if (empty($data->sections['description'])) {
    173             $data->sections['description'] = call_user_func(array($this_class, 'parse_markdown'), $data->short_description);
     183        if ( empty( $data->sections['description'] ) ) {
     184            $data->sections['description'] = call_user_func( array(
     185                $this_class,
     186                'parse_markdown'
     187            ), $data->short_description );
    174188        }
    175189
    176190        // Parse changelog
    177         if (!empty($data->sections['changelog'])) {
    178             $lines = explode("\n", $data->sections['changelog']);
    179             while (($line = array_shift($lines)) !== null) {
    180                 $trimmed = trim($line);
    181                 if (empty($trimmed)) {
     191        if ( ! empty( $data->sections['changelog'] ) ) {
     192            $lines = explode( "\n", $data->sections['changelog'] );
     193            while ( ( $line = array_shift( $lines ) ) !== null ) {
     194                $trimmed = trim( $line );
     195                if ( empty( $trimmed ) ) {
    182196                    continue;
    183197                }
    184198
    185                 if ($trimmed[0] === '=') {
    186                     if (!empty($current)) {
    187                         $data->changelog[$title] = trim($current);
     199                if ( $trimmed[0] === '=' ) {
     200                    if ( ! empty( $current ) ) {
     201                        $data->changelog[ $title ] = trim( $current );
    188202                    }
    189203
    190204                    $current = '';
    191                     $title = trim($line, "#= \t");
     205                    $title   = trim( $line, "#= \t" );
    192206                    continue;
    193207                }
     
    196210            }
    197211
    198             $data->changelog[$title] = trim($current);
    199         }
    200         $title = null;
     212            $data->changelog[ $title ] = trim( $current );
     213        }
     214        $title   = null;
    201215        $current = null;
    202216
    203         if (isset($data->sections['upgrade_notice'])) {
    204             $lines = explode("\n", $data->sections['upgrade_notice']);
    205             while (($line = array_shift($lines)) !== null) {
    206                 $trimmed = trim($line);
    207                 if (empty($trimmed)) {
     217        if ( isset( $data->sections['upgrade_notice'] ) ) {
     218            $lines = explode( "\n", $data->sections['upgrade_notice'] );
     219            while ( ( $line = array_shift( $lines ) ) !== null ) {
     220                $trimmed = trim( $line );
     221                if ( empty( $trimmed ) ) {
    208222                    continue;
    209223                }
    210224
    211                 if ($trimmed[0] === '=') {
    212                     if (!empty($current)) {
    213                         $data->upgrade_notice[$title] = trim($current);
     225                if ( $trimmed[0] === '=' ) {
     226                    if ( ! empty( $current ) ) {
     227                        $data->upgrade_notice[ $title ] = trim( $current );
    214228                    }
    215229
    216230                    $current = '';
    217                     $title = trim($line, "#= \t");
     231                    $title   = trim( $line, "#= \t" );
    218232                    continue;
    219233                }
     
    222236            }
    223237
    224             if (!empty($title) && !empty($current)) {
    225                 $data->upgrade_notice[$title] = trim($current);
    226             }
    227             unset($data->sections['upgrade_notice']);
     238            if ( ! empty( $title ) && ! empty( $current ) ) {
     239                $data->upgrade_notice[ $title ] = trim( $current );
     240            }
     241            unset( $data->sections['upgrade_notice'] );
    228242        }
    229243
    230244        // Markdownify!
    231 
    232         $data->sections = array_map(array($this_class, 'parse_markdown'), $data->sections);
    233         $data->changelog = array_map(array($this_class, 'parse_markdown'), $data->changelog);
    234         $data->upgrade_notice = array_map(array($this_class, 'parse_markdown'), $data->upgrade_notice);
    235 
    236         if (isset($data->sections['screenshots'])) {
    237             preg_match_all('#<li>(.*?)</li>#is', $data->sections['screenshots'], $screenshots, PREG_SET_ORDER);
    238             if ($screenshots) {
    239                 foreach ((array) $screenshots as $ss) {
    240                     $data->screenshots[] = trim($ss[1]);
    241                 }
    242             }
    243         }
    244 
    245         // Rearrange stuff
    246 
     245        $data->sections       = array_map( array( $this_class, 'parse_markdown' ), $data->sections );
     246        $data->changelog      = array_map( array( $this_class, 'parse_markdown' ), $data->changelog );
     247        $data->upgrade_notice = array_map( array( $this_class, 'parse_markdown' ), $data->upgrade_notice );
     248
     249        if ( isset( $data->sections['screenshots'] ) ) {
     250            preg_match_all( '#<li>(.*?)</li>#is', $data->sections['screenshots'], $screenshots, PREG_SET_ORDER );
     251            if ( $screenshots ) {
     252                foreach ( (array) $screenshots as $ss ) {
     253                    $data->screenshots[] = trim( $ss[1] );
     254                }
     255            }
     256        }
     257
     258        // Rearrange stuff.
    247259        $data->remaining_content = $data->sections;
    248         $data->sections = array();
    249 
    250         foreach ($special as $spec) {
    251             if (isset($data->remaining_content[$spec])) {
    252                 $data->sections[$spec] = $data->remaining_content[$spec];
    253                 unset($data->remaining_content[$spec]);
     260        $data->sections          = array();
     261
     262        foreach ( $special as $spec ) {
     263            if ( isset( $data->remaining_content[ $spec ] ) ) {
     264                $data->sections[ $spec ] = $data->remaining_content[ $spec ];
     265                unset( $data->remaining_content[ $spec ] );
    254266            }
    255267        }
     
    258270    }
    259271
    260     protected static function get_first_nonwhitespace(&$contents) {
    261         while (($line = array_shift($contents)) !== null) {
    262             $trimmed = trim($line);
    263             if (!empty($line)) {
     272    protected static function get_first_nonwhitespace( &$contents ) {
     273        while ( ( $line = array_shift( $contents ) ) !== null ) {
     274            $trimmed = trim( $line );
     275            if ( ! empty( $line ) ) {
    264276                break;
    265277            }
     
    269281    }
    270282
    271     protected static function strip_newlines($line) {
    272         return rtrim($line, "\r\n");
    273     }
    274 
    275     protected static function trim_short_desc(&$desc) {
    276         if (function_exists('mb_strlen') && function_exists('mb_substr')) {
    277             if (mb_strlen($desc) > 150) {
    278                 $desc = mb_substr($desc, 0, 150);
    279                 $desc = trim($desc);
     283    protected static function strip_newlines( $line ) {
     284        return rtrim( $line, "\r\n" );
     285    }
     286
     287    protected static function trim_short_desc( &$desc ) {
     288        if ( function_exists( 'mb_strlen' ) && function_exists( 'mb_substr' ) ) {
     289            if ( mb_strlen( $desc ) > 150 ) {
     290                $desc = mb_substr( $desc, 0, 150 );
     291                $desc = trim( $desc );
     292
    280293                return true;
    281294            }
    282         }
    283         else {
    284             if (strlen($desc) > 150) {
    285                 $desc = substr($desc, 0, 150);
    286                 $desc = trim($desc);
     295        } else {
     296            if ( strlen( $desc ) > 150 ) {
     297                $desc = substr( $desc, 0, 150 );
     298                $desc = trim( $desc );
     299
    287300                return true;
    288301            }
     
    292305    }
    293306
    294     protected static function parse_markdown($text) {
    295         $text = self::code_trick($text);
    296         $text = preg_replace('/^[\s]*=[\s]+(.+?)[\s]+=/m', "\n" . '<h4>$1</h4>' . "\n", $text);
    297         $text = Markdown(trim($text));
    298         return trim($text);
    299     }
    300 
    301     protected static function code_trick($text) {
     307    protected static function parse_markdown( $text ) {
     308        $text = self::code_trick( $text );
     309        $text = preg_replace( '/^[\s]*=[\s]+(.+?)[\s]+=/m', "\n" . '<h4>$1</h4>' . "\n", $text );
     310        $text = Markdown( trim( $text ) );
     311
     312        return trim( $text );
     313    }
     314
     315    protected static function code_trick( $text ) {
    302316        // If doing markdown, first take any user formatted code blocks and turn them into backticks so that
    303317        // markdown will preserve things like underscores in code blocks
    304         $text = preg_replace_callback("!(<pre><code>|<code>)(.*?)(</code></pre>|</code>)!s", array(__CLASS__, 'decodeit'), $text);
    305 
    306         $text = str_replace(array("\r\n", "\r"), "\n", $text);
     318        $text = preg_replace_callback( "!(<pre><code>|<code>)(.*?)(</code></pre>|</code>)!s", array( __CLASS__, 'decodeit' ), $text );
     319        $text = str_replace( array( "\r\n", "\r" ), "\n", $text );
     320
    307321        // Markdown can do inline code, we convert bbPress style block level code to Markdown style
    308         $text = preg_replace_callback("!(^|\n)([ \t]*?)`(.*?)`!s", array(__CLASS__, 'indent'), $text);
     322        $text = preg_replace_callback( "!(^|\n)([ \t]*?)`(.*?)`!s", array( __CLASS__, 'indent' ), $text );
     323
    309324        return $text;
    310325    }
    311326
    312     protected static function indent($matches) {
     327    protected static function indent( $matches ) {
    313328        $text = $matches[3];
    314         $text = preg_replace('|^|m', $matches[2] . '    ', $text);
     329        $text = preg_replace( '|^|m', $matches[2] . '    ', $text );
     330
    315331        return $matches[1] . $text;
    316332    }
    317333
    318     protected static function decodeit($matches) {
    319         $text = $matches[2];
    320         $trans_table = array_flip(get_html_translation_table(HTML_ENTITIES));
    321         $text = strtr($text, $trans_table);
    322         $text = str_replace('<br />', '', $text);
    323         $text = str_replace('&#38;', '&', $text);
    324         $text = str_replace('&#39;', "'", $text);
    325         if ( '<pre><code>' == $matches[1] )
     334    protected static function decodeit( $matches ) {
     335        $text        = $matches[2];
     336        $trans_table = array_flip( get_html_translation_table( HTML_ENTITIES ) );
     337        $text        = strtr( $text, $trans_table );
     338        $text        = str_replace( '<br />', '', $text );
     339        $text        = str_replace( '&#38;', '&', $text );
     340        $text        = str_replace( '&#39;', "'", $text );
     341
     342            if ( '<pre><code>' == $matches[1] ) {
    326343            $text = "\n$text\n";
     344        }
     345
    327346        return "`$text`";
    328347    }
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/readme-parser/compat.php

    r2499 r2501  
    11<?php
     2/**
     3 * WordPress.org Plugin Readme Parser.
     4 *
     5 * @package WPorg_Plugin_Directory
     6 */
    27
    3 if ( !defined('WORDPRESS_README_MARKDOWN') ) {
    4     define('WORDPRESS_README_MARKDOWN', dirname(__FILE__) . '/markdown.php');
     8if ( ! defined( 'WORDPRESS_README_MARKDOWN' ) ) {
     9    define( 'WORDPRESS_README_MARKDOWN', dirname( __FILE__ ) . '/markdown.php' );
    510}
    611
    7 require_once(dirname(__FILE__) . '/ReadmeParser.php');
     12require_once( dirname( __FILE__ ) . '/ReadmeParser.php' );
    813
    9 class _WordPress_org_Readme extends Baikonur_ReadmeParser {
    10     public static function parse_readme($file) {
    11         $contents = file($file);
    12         return self::parse_readme_contents($contents);
     14/**
     15 * Class WPorg_Readme
     16 */
     17class WPorg_Readme extends Baikonur_ReadmeParser {
     18
     19    /**
     20     * @access public
     21     *
     22     * @param string $file File name.
     23     * @return array
     24     */
     25    public static function parse_readme( $file ) {
     26        $contents = file( $file );
     27
     28        return self::parse_readme_contents( $contents );
    1329    }
    1430
    15     public static function parse_readme_contents($contents) {
    16         if (empty($contents)) {
     31    /**
     32     * @access public
     33     *
     34     * @param array $contents
     35     * @return array
     36     */
     37    public static function parse_readme_contents( $contents ) {
     38        if ( empty( $contents ) ) {
    1739            return array();
    1840        }
    1941
    20         $result = parent::parse_readme_contents($contents);
    21         foreach ($result->sections as &$section) {
    22             $section = self::filter_text($section);
    23         }
    24         if (!empty($result->upgrade_notice)) {
    25             foreach ($result->upgrade_notice as &$notice) {
    26                 $notice = self::sanitize_text($notice);
    27             }
    28         }
    29         if (!empty($result->screenshots)) {
    30             foreach ($result->screenshots as &$shot) {
    31                 $shot = self::filter_text($shot);
    32             }
     42        $result = parent::parse_readme_contents( $contents );
     43        $result->sections = array_map( array( 'WPorg_Readme', 'filter_text' ), $result->sections );
     44
     45        if ( ! empty( $result->upgrade_notice ) ) {
     46            $result->upgrade_notice = array_map( array( 'WPorg_Readme', 'sanitize_text' ), $result->upgrade_notice );
    3347        }
    3448
    35         if (!empty($result->remaining_content)) {
    36             $result->remaining_content = implode("\n", $result->remaining_content);
    37             $result->remaining_content = self::filter_text(str_replace("</h3>\n\n", "</h3>\n", $result->remaining_content));
     49        if ( ! empty( $result->screenshots ) ) {
     50            $result->screenshots = array_map( array( 'WPorg_Readme', 'filter_text' ), $result->screenshots );
    3851        }
    39         else {
     52
     53        if ( ! empty( $result->remaining_content ) ) {
     54            $result->remaining_content = implode( "\n", $result->remaining_content );
     55            $result->remaining_content = self::filter_text( str_replace( "</h3>\n\n", "</h3>\n", $result->remaining_content ) );
     56        } else {
    4057            $result->remaining_content = '';
    4158        }
    4259
    43         $result->name = self::sanitize_text($result->name);
     60        $result->name = self::sanitize_text( $result->name );
    4461        //$result->short_description = self::sanitize_text($result->short_description);
    45         $result->donate_link = esc_url($result->donate_link);
     62        $result->donate_link = esc_url( $result->donate_link );
    4663
    4764        $result->requires_at_least = $result->requires;
    48         $result->tested_up_to = $result->tested;
    49         unset($result->requires, $result->tested);
    50         $result = ((array) $result);
    51         return $result;
     65        $result->tested_up_to      = $result->tested;
     66
     67        unset( $result->requires, $result->tested );
     68
     69        return (array) $result;
    5270    }
    5371
    54     protected static function trim_short_desc(&$desc) {
    55         $desc = self::sanitize_text($desc);
    56         return parent::trim_short_desc($desc);
     72    /**
     73     * @access protected
     74     *
     75     * @param string $desc
     76     * @return string
     77     */
     78    protected static function trim_short_desc( &$desc ) {
     79        $desc = self::sanitize_text( $desc );
     80        parent::trim_short_desc( $desc );
     81
     82        return $desc;
    5783    }
    5884
     85    /**
     86     * @access protected
     87     *
     88     * @param string $text
     89     * @return string
     90     */
    5991    protected static function sanitize_text( $text ) { // not fancy
    60         $text = strip_tags($text);
    61         $text = esc_html($text);
    62         $text = trim($text);
     92        $text = strip_tags( $text );
     93        $text = esc_html( $text );
     94        $text = trim( $text );
     95
    6396        return $text;
    6497    }
    6598
     99    /**
     100     * @access protected
     101     *
     102     * @param string $text
     103     * @return string
     104     */
    66105    protected static function filter_text( $text ) {
    67         $text = trim($text);
     106        $text = trim( $text );
    68107        //$text = self::code_trick($text); // A better parser than Markdown's for: backticks -> CODE
    69108
    70109        $allowed = array(
    71             'a' => array(
    72                 'href' => array(),
     110            'a'          => array(
     111                'href'  => array(),
    73112                'title' => array(),
    74                 'rel' => array()),
    75             'blockquote' => array('cite' => array()),
    76             'br' => array(),
    77             'p' => array(),
    78             'code' => array(),
    79             'pre' => array(),
    80             'em' => array(),
    81             'strong' => array(),
    82             'ul' => array(),
    83             'ol' => array(),
    84             'li' => array(),
    85             'h3' => array(),
    86             'h4' => array()
     113                'rel'   => array()
     114            ),
     115            'blockquote' => array( 'cite' => array() ),
     116            'br'         => array(),
     117            'p'          => array(),
     118            'code'       => array(),
     119            'pre'        => array(),
     120            'em'         => array(),
     121            'strong'     => array(),
     122            'ul'         => array(),
     123            'ol'         => array(),
     124            'li'         => array(),
     125            'h3'         => array(),
     126            'h4'         => array(),
    87127        );
    88128
    89         $text = balanceTags($text);
     129        $text = balanceTags( $text );
    90130
    91131        $text = wp_kses( $text, $allowed );
    92         $text = trim($text);
     132        $text = trim( $text );
     133
    93134        return $text;
    94135    }
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/readme-parser/markdown.php

    r2499 r2501  
    44#
    55# PHP Markdown & Extra
    6 # Copyright (c) 2004-2009 Michel Fortin 
     6# Copyright (c) 2004-2009 Michel Fortin
    77# <http://michelf.com/projects/php-markdown/>
    88#
    99# Original Markdown
    10 # Copyright (c) 2004-2006 John Gruber 
     10# Copyright (c) 2004-2006 John Gruber
    1111# <http://daringfireball.net/projects/markdown/>
    1212#
    1313
    14 
    15 define( 'MARKDOWN_VERSION',  "1.0.1n" ); # Sat 10 Oct 2009
    16 define( 'MARKDOWNEXTRA_VERSION',  "1.2.4" ); # Sat 10 Oct 2009
    17 
     14define( 'MARKDOWN_VERSION', "1.0.1n" ); # Sat 10 Oct 2009
     15define( 'MARKDOWNEXTRA_VERSION', "1.2.4" ); # Sat 10 Oct 2009
    1816
    1917#
     
    2220
    2321# Change to ">" for HTML output
    24 @define( 'MARKDOWN_EMPTY_ELEMENT_SUFFIX',  " />");
     22@define( 'MARKDOWN_EMPTY_ELEMENT_SUFFIX', " />" );
    2523
    2624# Define the width of a tab for code blocks.
    27 @define( 'MARKDOWN_TAB_WIDTH',     4 );
     25@define( 'MARKDOWN_TAB_WIDTH', 4 );
    2826
    2927# Optional title attribute for footnote links and backlinks.
    30 @define( 'MARKDOWN_FN_LINK_TITLE',         "" );
    31 @define( 'MARKDOWN_FN_BACKLINK_TITLE',     "" );
     28@define( 'MARKDOWN_FN_LINK_TITLE', "" );
     29@define( 'MARKDOWN_FN_BACKLINK_TITLE', "" );
    3230
    3331# Optional class attribute for footnote links and backlinks.
    34 @define( 'MARKDOWN_FN_LINK_CLASS',         "" );
    35 @define( 'MARKDOWN_FN_BACKLINK_CLASS',     "" );
    36 
     32@define( 'MARKDOWN_FN_LINK_CLASS', "" );
     33@define( 'MARKDOWN_FN_BACKLINK_CLASS', "" );
    3734
    3835#
     
    4138
    4239# Change to false to remove Markdown from posts and/or comments.
    43 @define( 'MARKDOWN_WP_POSTS',      true );
    44 @define( 'MARKDOWN_WP_COMMENTS',   true );
    45 
    46 
     40@define( 'MARKDOWN_WP_POSTS', true );
     41@define( 'MARKDOWN_WP_COMMENTS', true );
    4742
    4843### Standard Function Interface ###
    4944
    50 @define( 'MARKDOWN_PARSER_CLASS',  'MarkdownExtra_Parser' );
    51 
    52 function Markdown($text) {
     45@define( 'MARKDOWN_PARSER_CLASS', 'MarkdownExtra_Parser' );
     46
     47function Markdown( $text ) {
    5348#
    5449# Initialize the parser and return the result of its transform method.
     
    5651    # Setup static parser variable.
    5752    static $parser;
    58     if (!isset($parser)) {
     53    if ( ! isset( $parser ) ) {
    5954        $parser_class = MARKDOWN_PARSER_CLASS;
    60         $parser = new $parser_class;
     55        $parser       = new $parser_class;
    6156    }
    6257
    6358    # Transform text using parser.
    64     return $parser->transform($text);
     59    return $parser->transform( $text );
    6560}
    66 
    6761
    6862### WordPress Plugin Interface ###
     
    7771*/
    7872
    79 if (isset($wp_version)) {
     73if ( isset( $wp_version ) ) {
    8074    # More details about how it works here:
    8175    # <http://michelf.com/weblog/2005/wordpress-text-flow-vs-markdown/>
    82    
     76
    8377    # Post content and excerpts
    8478    # - Remove WordPress paragraph generator.
    8579    # - Run Markdown on excerpt, then remove all tags.
    8680    # - Add paragraph tag around the excerpt, but remove it for the excerpt rss.
    87     if (MARKDOWN_WP_POSTS) {
    88         remove_filter('the_content',     'wpautop');
    89         remove_filter('the_content_rss', 'wpautop');
    90         remove_filter('the_excerpt',     'wpautop');
    91         add_filter('the_content',     'mdwp_MarkdownPost', 6);
    92         add_filter('the_content_rss', 'mdwp_MarkdownPost', 6);
    93         add_filter('get_the_excerpt', 'mdwp_MarkdownPost', 6);
    94         add_filter('get_the_excerpt', 'trim', 7);
    95         add_filter('the_excerpt',     'mdwp_add_p');
    96         add_filter('the_excerpt_rss', 'mdwp_strip_p');
    97        
    98         remove_filter('content_save_pre',  'balanceTags', 50);
    99         remove_filter('excerpt_save_pre',  'balanceTags', 50);
    100         add_filter('the_content',     'balanceTags', 50);
    101         add_filter('get_the_excerpt', 'balanceTags', 9);
    102     }
    103    
     81    if ( MARKDOWN_WP_POSTS ) {
     82        remove_filter( 'the_content', 'wpautop' );
     83        remove_filter( 'the_content_rss', 'wpautop' );
     84        remove_filter( 'the_excerpt', 'wpautop' );
     85        add_filter( 'the_content', 'mdwp_MarkdownPost', 6 );
     86        add_filter( 'the_content_rss', 'mdwp_MarkdownPost', 6 );
     87        add_filter( 'get_the_excerpt', 'mdwp_MarkdownPost', 6 );
     88        add_filter( 'get_the_excerpt', 'trim', 7 );
     89        add_filter( 'the_excerpt', 'mdwp_add_p' );
     90        add_filter( 'the_excerpt_rss', 'mdwp_strip_p' );
     91
     92        remove_filter( 'content_save_pre', 'balanceTags', 50 );
     93        remove_filter( 'excerpt_save_pre', 'balanceTags', 50 );
     94        add_filter( 'the_content', 'balanceTags', 50 );
     95        add_filter( 'get_the_excerpt', 'balanceTags', 9 );
     96    }
     97
    10498    # Add a footnote id prefix to posts when inside a loop.
    105     function mdwp_MarkdownPost($text) {
     99    function mdwp_MarkdownPost( $text ) {
    106100        static $parser;
    107         if (!$parser) {
     101        if ( ! $parser ) {
    108102            $parser_class = MARKDOWN_PARSER_CLASS;
    109             $parser = new $parser_class;
    110         }
    111         if (is_single() || is_page() || is_feed()) {
     103            $parser       = new $parser_class;
     104        }
     105        if ( is_single() || is_page() || is_feed() ) {
    112106            $parser->fn_id_prefix = "";
    113107        } else {
    114108            $parser->fn_id_prefix = get_the_ID() . ".";
    115109        }
    116         return $parser->transform($text);
    117     }
    118    
     110
     111        return $parser->transform( $text );
     112    }
     113
    119114    # Comments
    120115    # - Remove WordPress paragraph generator.
     
    122117    # - Scramble important tags before passing them to the kses filter.
    123118    # - Run Markdown on excerpt then remove paragraph tags.
    124     if (MARKDOWN_WP_COMMENTS) {
    125         remove_filter('comment_text', 'wpautop', 30);
    126         remove_filter('comment_text', 'make_clickable');
    127         add_filter('pre_comment_content', 'Markdown', 6);
    128         add_filter('pre_comment_content', 'mdwp_hide_tags', 8);
    129         add_filter('pre_comment_content', 'mdwp_show_tags', 12);
    130         add_filter('get_comment_text',    'Markdown', 6);
    131         add_filter('get_comment_excerpt', 'Markdown', 6);
    132         add_filter('get_comment_excerpt', 'mdwp_strip_p', 7);
    133    
     119    if ( MARKDOWN_WP_COMMENTS ) {
     120        remove_filter( 'comment_text', 'wpautop', 30 );
     121        remove_filter( 'comment_text', 'make_clickable' );
     122        add_filter( 'pre_comment_content', 'Markdown', 6 );
     123        add_filter( 'pre_comment_content', 'mdwp_hide_tags', 8 );
     124        add_filter( 'pre_comment_content', 'mdwp_show_tags', 12 );
     125        add_filter( 'get_comment_text', 'Markdown', 6 );
     126        add_filter( 'get_comment_excerpt', 'Markdown', 6 );
     127        add_filter( 'get_comment_excerpt', 'mdwp_strip_p', 7 );
     128
    134129        global $mdwp_hidden_tags, $mdwp_placeholders;
    135         $mdwp_hidden_tags = explode(' ',
    136             '<p> </p> <pre> </pre> <ol> </ol> <ul> </ul> <li> </li>');
    137         $mdwp_placeholders = explode(' ', str_rot13(
    138             'pEj07ZbbBZ U1kqgh4w4p pre2zmeN6K QTi31t9pre ol0MP1jzJR '.
    139             'ML5IjmbRol ulANi1NsGY J7zRLJqPul liA8ctl16T K9nhooUHli'));
    140     }
    141    
    142     function mdwp_add_p($text) {
    143         if (!preg_match('{^$|^<(p|ul|ol|dl|pre|blockquote)>}i', $text)) {
    144             $text = '<p>'.$text.'</p>';
    145             $text = preg_replace('{\n{2,}}', "</p>\n\n<p>", $text);
    146         }
     130        $mdwp_hidden_tags  = explode( ' ',
     131            '<p> </p> <pre> </pre> <ol> </ol> <ul> </ul> <li> </li>' );
     132        $mdwp_placeholders = explode( ' ', str_rot13(
     133            'pEj07ZbbBZ U1kqgh4w4p pre2zmeN6K QTi31t9pre ol0MP1jzJR ' .
     134            'ML5IjmbRol ulANi1NsGY J7zRLJqPul liA8ctl16T K9nhooUHli' ) );
     135    }
     136
     137    function mdwp_add_p( $text ) {
     138        if ( ! preg_match( '{^$|^<(p|ul|ol|dl|pre|blockquote)>}i', $text ) ) {
     139            $text = '<p>' . $text . '</p>';
     140            $text = preg_replace( '{\n{2,}}', "</p>\n\n<p>", $text );
     141        }
     142
    147143        return $text;
    148144    }
    149    
    150     function mdwp_strip_p($t) { return preg_replace('{</?p>}i', '', $t); }
    151 
    152     function mdwp_hide_tags($text) {
     145
     146    function mdwp_strip_p( $t ) {
     147        return preg_replace( '{</?p>}i', '', $t );
     148    }
     149
     150    function mdwp_hide_tags( $text ) {
    153151        global $mdwp_hidden_tags, $mdwp_placeholders;
    154         return str_replace($mdwp_hidden_tags, $mdwp_placeholders, $text);
    155     }
    156     function mdwp_show_tags($text) {
     152
     153        return str_replace( $mdwp_hidden_tags, $mdwp_placeholders, $text );
     154    }
     155
     156    function mdwp_show_tags( $text ) {
    157157        global $mdwp_hidden_tags, $mdwp_placeholders;
    158         return str_replace($mdwp_placeholders, $mdwp_hidden_tags, $text);
     158
     159        return str_replace( $mdwp_placeholders, $mdwp_hidden_tags, $text );
    159160    }
    160161}
    161 
    162162
    163163### bBlog Plugin Info ###
     
    165165function identify_modifier_markdown() {
    166166    return array(
    167         'name' => 'markdown',
    168         'type' => 'modifier',
    169         'nicename' => 'PHP Markdown Extra',
     167        'name'        => 'markdown',
     168        'type'        => 'modifier',
     169        'nicename'    => 'PHP Markdown Extra',
    170170        'description' => 'A text-to-HTML conversion tool for web writers',
    171         'authors' => 'Michel Fortin and John Gruber',
    172         'licence' => 'GPL',
    173         'version' => MARKDOWNEXTRA_VERSION,
    174         'help' => '<a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://michelf.com/projects/php-markdown/">More...</a>',
    175         );
     171        'authors'     => 'Michel Fortin and John Gruber',
     172        'licence'     => 'GPL',
     173        'version'     => MARKDOWNEXTRA_VERSION,
     174        'help'        => '<a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://michelf.com/projects/php-markdown/">More...</a>',
     175    );
    176176}
    177177
    178 
    179178### Smarty Modifier Interface ###
    180179
    181 function smarty_modifier_markdown($text) {
    182     return Markdown($text);
     180function smarty_modifier_markdown( $text ) {
     181    return Markdown( $text );
    183182}
    184183
    185 
    186184### Textile Compatibility Mode ###
    187185
    188186# Rename this file to "classTextile.php" and it can replace Textile everywhere.
    189187
    190 if (strcasecmp(substr(__FILE__, -16), "classTextile.php") == 0) {
     188if ( strcasecmp( substr( __FILE__, - 16 ), "classTextile.php" ) == 0 ) {
    191189    # Try to include PHP SmartyPants. Should be in the same directory.
    192190    @include_once 'smartypants.php';
     191
    193192    # Fake Textile class. It calls Markdown instead.
    194193    class Textile {
    195         function TextileThis($text, $lite='', $encode='') {
    196             if ($lite == '' && $encode == '')    $text = Markdown($text);
    197             if (function_exists('SmartyPants'))  $text = SmartyPants($text);
     194        function TextileThis( $text, $lite = '', $encode = '' ) {
     195            if ( $lite == '' && $encode == '' ) {
     196                $text = Markdown( $text );
     197            }
     198            if ( function_exists( 'SmartyPants' ) ) {
     199                $text = SmartyPants( $text );
     200            }
     201
    198202            return $text;
    199203        }
     204
    200205        # Fake restricted version: restrictions are not supported for now.
    201         function TextileRestricted($text, $lite='', $noimage='') {
    202             return $this->TextileThis($text, $lite);
    203         }
     206        function TextileRestricted( $text, $lite = '', $noimage = '' ) {
     207            return $this->TextileThis( $text, $lite );
     208        }
     209
    204210        # Workaround to ensure compatibility with TextPattern 4.0.3.
    205         function blockLite($text) { return $text; }
     211        function blockLite( $text ) {
     212            return $text;
     213        }
    206214    }
    207215}
    208 
    209 
    210216
    211217#
     
    214220
    215221class Markdown_Parser {
    216 
    217222    # Regex to match balanced [brackets].
    218223    # Needed to insert a maximum bracked depth while converting to PHP.
    219224    var $nested_brackets_depth = 6;
    220225    var $nested_brackets_re;
    221    
    222226    var $nested_url_parenthesis_depth = 4;
    223227    var $nested_url_parenthesis_re;
    224 
    225228    # Table of hash values for escaped characters:
    226229    var $escape_chars = '\`*_{}[]()>#+-.!';
    227230    var $escape_chars_re;
    228 
    229231    # Change to ">" for HTML output.
    230232    var $empty_element_suffix = MARKDOWN_EMPTY_ELEMENT_SUFFIX;
    231233    var $tab_width = MARKDOWN_TAB_WIDTH;
    232    
    233234    # Change to `true` to disallow markup or entities.
    234235    var $no_markup = false;
    235236    var $no_entities = false;
    236    
    237237    # Predefined urls and titles for reference links and images.
    238238    var $predef_urls = array();
    239239    var $predef_titles = array();
    240240
    241 
    242241    function Markdown_Parser() {
    243     #
    244     # Constructor function. Initialize appropriate member variables.
    245     #
     242        #
     243        # Constructor function. Initialize appropriate member variables.
     244        #
    246245        $this->_initDetab();
    247246        $this->prepareItalicsAndBold();
    248    
    249         $this->nested_brackets_re = 
    250             str_repeat('(?>[^\[\]]+|\[', $this->nested_brackets_depth).
    251             str_repeat('\])*', $this->nested_brackets_depth);
    252    
    253         $this->nested_url_parenthesis_re = 
    254             str_repeat('(?>[^()\s]+|\(', $this->nested_url_parenthesis_depth).
    255             str_repeat('(?>\)))*', $this->nested_url_parenthesis_depth);
    256        
    257         $this->escape_chars_re = '['.preg_quote($this->escape_chars).']';
    258        
     247
     248        $this->nested_brackets_re =
     249            str_repeat( '(?>[^\[\]]+|\[', $this->nested_brackets_depth ) .
     250            str_repeat( '\])*', $this->nested_brackets_depth );
     251
     252        $this->nested_url_parenthesis_re =
     253            str_repeat( '(?>[^()\s]+|\(', $this->nested_url_parenthesis_depth ) .
     254            str_repeat( '(?>\)))*', $this->nested_url_parenthesis_depth );
     255
     256        $this->escape_chars_re = '[' . preg_quote( $this->escape_chars ) . ']';
     257
    259258        # Sort document, block, and span gamut in ascendent priority order.
    260         asort($this->document_gamut);
    261         asort($this->block_gamut);
    262         asort($this->span_gamut);
    263     }
    264 
     259        asort( $this->document_gamut );
     260        asort( $this->block_gamut );
     261        asort( $this->span_gamut );
     262    }
    265263
    266264    # Internal hashes used during transformation.
     
    268266    var $titles = array();
    269267    var $html_hashes = array();
    270    
    271268    # Status flag to avoid invalid nesting.
    272269    var $in_anchor = false;
    273    
    274    
     270
    275271    function setup() {
    276     #
    277     # Called before the transformation process starts to setup parser
    278     # states.
    279     #
     272        #
     273        # Called before the transformation process starts to setup parser
     274        # states.
     275        #
    280276        # Clear global hashes.
    281         $this->urls = $this->predef_urls;
    282         $this->titles = $this->predef_titles;
     277        $this->urls        = $this->predef_urls;
     278        $this->titles      = $this->predef_titles;
    283279        $this->html_hashes = array();
    284        
     280
    285281        $in_anchor = false;
    286282    }
    287    
     283
    288284    function teardown() {
    289     #
    290     # Called after the transformation process to clear any variable
    291     # which may be taking up memory unnecessarly.
    292     #
    293         $this->urls = array();
    294         $this->titles = array();
     285        #
     286        # Called after the transformation process to clear any variable
     287        # which may be taking up memory unnecessarly.
     288        #
     289        $this->urls        = array();
     290        $this->titles      = array();
    295291        $this->html_hashes = array();
    296292    }
    297293
    298 
    299     function transform($text) {
    300     #
    301     # Main function. Performs some preprocessing on the input text
    302     # and pass it through the document gamut.
    303     #
     294    function transform( $text ) {
     295        #
     296        # Main function. Performs some preprocessing on the input text
     297        # and pass it through the document gamut.
     298        #
    304299        $this->setup();
    305    
     300
    306301        # Remove UTF-8 BOM and marker character in input, if present.
    307         $text = preg_replace('{^\xEF\xBB\xBF|\x1A}', '', $text);
     302        $text = preg_replace( '{^\xEF\xBB\xBF|\x1A}', '', $text );
    308303
    309304        # Standardize line endings:
    310305        #   DOS to Unix and Mac to Unix
    311         $text = preg_replace('{\r\n?}', "\n", $text);
     306        $text = preg_replace( '{\r\n?}', "\n", $text );
    312307
    313308        # Make sure $text ends with a couple of newlines:
     
    315310
    316311        # Convert all tabs to spaces.
    317         $text = $this->detab($text);
     312        $text = $this->detab( $text );
    318313
    319314        # Turn block-level HTML blocks into hash entries
    320         $text = $this->hashHTMLBlocks($text);
     315        $text = $this->hashHTMLBlocks( $text );
    321316
    322317        # Strip any lines consisting only of spaces and tabs.
     
    324319        # match consecutive blank lines with /\n+/ instead of something
    325320        # contorted like /[ ]*\n+/ .
    326         $text = preg_replace('/^[ ]+$/m', '', $text);
     321        $text = preg_replace( '/^[ ]+$/m', '', $text );
    327322
    328323        # Run document gamut methods.
    329         foreach ($this->document_gamut as $method => $priority) {
    330             $text = $this->$method($text);
    331         }
    332        
     324        foreach ( $this->document_gamut as $method => $priority ) {
     325            $text = $this->$method( $text );
     326        }
     327
    333328        $this->teardown();
    334329
    335330        return $text . "\n";
    336331    }
    337    
     332
    338333    var $document_gamut = array(
    339334        # Strip link definitions, store in hashes.
    340335        "stripLinkDefinitions" => 20,
    341        
    342336        "runBasicBlockGamut"   => 30,
    343         );
    344 
    345 
    346     function stripLinkDefinitions($text) {
    347     #
    348     # Strips link definitions from text, stores the URLs and titles in
    349     # hash references.
    350     #
     337    );
     338
     339    function stripLinkDefinitions( $text ) {
     340        #
     341        # Strips link definitions from text, stores the URLs and titles in
     342        # hash references.
     343        #
    351344        $less_than_tab = $this->tab_width - 1;
    352345
    353346        # Link defs are in the form: ^[id]: url "optional title"
    354         $text = preg_replace_callback('{
    355                             ^[ ]{0,'.$less_than_tab.'}\[(.+)\][ ]?: # id = $1
     347        $text = preg_replace_callback( '{
     348                            ^[ ]{0,' . $less_than_tab . '}\[(.+)\][ ]?: # id = $1
    356349                              [ ]*
    357350                              \n?               # maybe *one* newline
     
    374367                            (?:\n+|\Z)
    375368            }xm',
    376             array(&$this, '_stripLinkDefinitions_callback'),
    377             $text);
     369            array( &$this, '_stripLinkDefinitions_callback' ),
     370            $text );
     371
    378372        return $text;
    379373    }
    380     function _stripLinkDefinitions_callback($matches) {
    381         $link_id = strtolower($matches[1]);
    382         $url = $matches[2] == '' ? $matches[3] : $matches[2];
    383         $this->urls[$link_id] = $url;
    384         $this->titles[$link_id] =& $matches[4];
     374
     375    function _stripLinkDefinitions_callback( $matches ) {
     376        $link_id                  = strtolower( $matches[1] );
     377        $url                      = $matches[2] == '' ? $matches[3] : $matches[2];
     378        $this->urls[ $link_id ]   = $url;
     379        $this->titles[ $link_id ] =& $matches[4];
     380
    385381        return ''; # String that will replace the block
    386382    }
    387383
    388 
    389     function hashHTMLBlocks($text) {
    390         if ($this->no_markup)  return $text;
     384    function hashHTMLBlocks( $text ) {
     385        if ( $this->no_markup ) {
     386            return $text;
     387        }
    391388
    392389        $less_than_tab = $this->tab_width - 1;
     
    400397        #
    401398        # *  List "a" is made of tags which can be both inline or block-level.
    402         #    These will be treated block-level when the start tag is alone on 
    403         #    its line, otherwise they're not matched here and will be taken as 
     399        #    These will be treated block-level when the start tag is alone on
     400        #    its line, otherwise they're not matched here and will be taken as
    404401        #    inline later.
    405402        # *  List "b" is made of tags which are always block-level;
    406403        #
    407404        $block_tags_a_re = 'ins|del';
    408         $block_tags_b_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|'.
    409                            'script|noscript|form|fieldset|iframe|math';
     405        $block_tags_b_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|' .
     406                           'script|noscript|form|fieldset|iframe|math';
    410407
    411408        # Regular expression for the content of a block tag.
    412409        $nested_tags_level = 4;
    413         $attr = '
     410        $attr              = '
    414411            (?>             # optional tag attributes
    415412              \s            # starts with whitespace
     
    423420                \'[^\']*\'  # text inside single quotes (tolerate ">")
    424421              )*
    425             )? 
     422            )?
    426423            ';
    427         $content =
    428             str_repeat('
     424        $content           =
     425            str_repeat( '
    429426                (?>
    430427                  [^<]+         # content without tag
    431428                |
    432429                  <\2           # nested opening tag
    433                     '.$attr.'   # attributes
     430                    ' . $attr . '   # attributes
    434431                    (?>
    435432                      />
    436433                    |
    437                       >', $nested_tags_level).  # end of opening tag
    438                       '.*?'.                    # last level nested tag content
    439             str_repeat('
     434                      >', $nested_tags_level ) .    # end of opening tag
     435            '.*?' .                    # last level nested tag content
     436            str_repeat( '
    440437                      </\2\s*>  # closing nested tag
    441438                    )
    442                   |             
     439                  |
    443440                    <(?!/\2\s*> # other tags with a different name
    444441                  )
    445442                )*',
    446                 $nested_tags_level);
    447         $content2 = str_replace('\2', '\3', $content);
     443                $nested_tags_level );
     444        $content2          = str_replace( '\2', '\3', $content );
    448445
    449446        # First, look for nested blocks, e.g.:
     
    458455        # We need to do this before the next, more liberal match, because the next
    459456        # match will start at the first `<div>` and stop at the first `</div>`.
    460         $text = preg_replace_callback('{(?>
     457        $text = preg_replace_callback( '{(?>
    461458            (?>
    462459                (?<=\n\n)       # Starting after a blank line
     
    466463            (                       # save in $1
    467464
    468               # Match from `\n<tag>` to `</tag>\n`, handling nested tags 
     465              # Match from `\n<tag>` to `</tag>\n`, handling nested tags
    469466              # in between.
    470                    
    471                         [ ]{0,'.$less_than_tab.'}
    472                         <('.$block_tags_b_re.')# start tag = $2
    473                         '.$attr.'>          # attributes followed by > and \n
    474                         '.$content.'        # content, support nesting
     467
     468                        [ ]{0,' . $less_than_tab . '}
     469                        <(' . $block_tags_b_re . ')# start tag = $2
     470                        ' . $attr . '>          # attributes followed by > and \n
     471                        ' . $content . '        # content, support nesting
    475472                        </\2>               # the matching end tag
    476473                        [ ]*                # trailing spaces/tabs
     
    479476            | # Special version for tags of group a.
    480477
    481                         [ ]{0,'.$less_than_tab.'}
    482                         <('.$block_tags_a_re.')# start tag = $3
    483                         '.$attr.'>[ ]*\n    # attributes followed by >
    484                         '.$content2.'       # content, support nesting
     478                        [ ]{0,' . $less_than_tab . '}
     479                        <(' . $block_tags_a_re . ')# start tag = $3
     480                        ' . $attr . '>[ ]*\n    # attributes followed by >
     481                        ' . $content2 . '       # content, support nesting
    485482                        </\3>               # the matching end tag
    486483                        [ ]*                # trailing spaces/tabs
    487484                        (?=\n+|\Z)  # followed by a newline or end of document
    488                    
    489             | # Special case just for <hr />. It was easier to make a special 
     485
     486            | # Special case just for <hr />. It was easier to make a special
    490487              # case than to make the other regex more complicated.
    491            
    492                         [ ]{0,'.$less_than_tab.'}
     488
     489                        [ ]{0,' . $less_than_tab . '}
    493490                        <(hr)               # start tag = $2
    494                         '.$attr.'           # attributes
     491                        ' . $attr . '           # attributes
    495492                        /?>                 # the matching end tag
    496493                        [ ]*
    497494                        (?=\n{2,}|\Z)       # followed by a blank line or end of document
    498            
     495
    499496            | # Special case for standalone HTML comments:
    500            
    501                     [ ]{0,'.$less_than_tab.'}
     497
     498                    [ ]{0,' . $less_than_tab . '}
    502499                    (?s:
    503500                        <!-- .*? -->
     
    505502                    [ ]*
    506503                    (?=\n{2,}|\Z)       # followed by a blank line or end of document
    507            
     504
    508505            | # PHP and ASP-style processor instructions (<? and <%)
    509            
    510                     [ ]{0,'.$less_than_tab.'}
     506
     507                    [ ]{0,' . $less_than_tab . '}
    511508                    (?s:
    512509                        <([?%])         # $2
     
    516513                    [ ]*
    517514                    (?=\n{2,}|\Z)       # followed by a blank line or end of document
    518                    
     515
    519516            )
    520517            )}Sxmi',
    521             array(&$this, '_hashHTMLBlocks_callback'),
    522             $text);
     518            array( &$this, '_hashHTMLBlocks_callback' ),
     519            $text );
    523520
    524521        return $text;
    525522    }
    526     function _hashHTMLBlocks_callback($matches) {
     523
     524    function _hashHTMLBlocks_callback( $matches ) {
    527525        $text = $matches[1];
    528         $key  = $this->hashBlock($text);
     526        $key  = $this->hashBlock( $text );
     527
    529528        return "\n\n$key\n\n";
    530529    }
    531    
    532    
    533     function hashPart($text, $boundary = 'X') {
    534     #
    535     # Called whenever a tag must be hashed when a function insert an atomic
    536     # element in the text stream. Passing $text to through this function gives
    537     # a unique text-token which will be reverted back when calling unhash.
    538     #
    539     # The $boundary argument specify what character should be used to surround
    540     # the token. By convension, "B" is used for block elements that needs not
    541     # to be wrapped into paragraph tags at the end, ":" is used for elements
    542     # that are word separators and "X" is used in the general case.
    543     #
     530
     531    function hashPart( $text, $boundary = 'X' ) {
     532        #
     533        # Called whenever a tag must be hashed when a function insert an atomic
     534        # element in the text stream. Passing $text to through this function gives
     535        # a unique text-token which will be reverted back when calling unhash.
     536        #
     537        # The $boundary argument specify what character should be used to surround
     538        # the token. By convension, "B" is used for block elements that needs not
     539        # to be wrapped into paragraph tags at the end, ":" is used for elements
     540        # that are word separators and "X" is used in the general case.
     541        #
    544542        # Swap back any tag hash found in $text so we do not have to `unhash`
    545543        # multiple times at the end.
    546         $text = $this->unhash($text);
    547        
     544        $text = $this->unhash( $text );
     545
    548546        # Then hash the block.
    549547        static $i = 0;
    550         $key = "$boundary\x1A" . ++$i . $boundary;
    551         $this->html_hashes[$key] = $text;
     548        $key                       = "$boundary\x1A" . ++ $i . $boundary;
     549        $this->html_hashes[ $key ] = $text;
     550
    552551        return $key; # String that will replace the tag.
    553552    }
    554553
    555 
    556     function hashBlock($text) {
    557     #
    558     # Shortcut function for hashPart with block-level boundaries.
    559     #
    560         return $this->hashPart($text, 'B');
    561     }
    562 
     554    function hashBlock( $text ) {
     555        #
     556        # Shortcut function for hashPart with block-level boundaries.
     557        #
     558        return $this->hashPart( $text, 'B' );
     559    }
    563560
    564561    var $block_gamut = array(
    565     #
    566     # These are all the transformations that form block-level
    567     # tags like paragraphs, headers, and list items.
    568     #
     562        #
     563        # These are all the transformations that form block-level
     564        # tags like paragraphs, headers, and list items.
     565        #
    569566        "doHeaders"         => 10,
    570567        "doHorizontalRules" => 20,
    571        
    572568        "doLists"           => 40,
    573569        "doCodeBlocks"      => 50,
    574570        "doBlockQuotes"     => 60,
    575         );
    576 
    577     function runBlockGamut($text) {
    578     #
    579     # Run block gamut tranformations.
    580     #
    581         # We need to escape raw HTML in Markdown source before doing anything 
    582         # else. This need to be done for each block, and not only at the 
     571    );
     572
     573    function runBlockGamut( $text ) {
     574        #
     575        # Run block gamut tranformations.
     576        #
     577        # We need to escape raw HTML in Markdown source before doing anything
     578        # else. This need to be done for each block, and not only at the
    583579        # begining in the Markdown function since hashed blocks can be part of
    584         # list items and could have been indented. Indented blocks would have 
     580        # list items and could have been indented. Indented blocks would have
    585581        # been seen as a code block in a previous pass of hashHTMLBlocks.
    586         $text = $this->hashHTMLBlocks($text);
    587        
    588         return $this->runBasicBlockGamut($text);
    589     }
    590    
    591     function runBasicBlockGamut($text) {
    592     #
    593     # Run block gamut tranformations, without hashing HTML blocks. This is
    594     # useful when HTML blocks are known to be already hashed, like in the first
    595     # whole-document pass.
    596     #
    597         foreach ($this->block_gamut as $method => $priority) {
    598             $text = $this->$method($text);
    599         }
    600        
     582        $text = $this->hashHTMLBlocks( $text );
     583
     584        return $this->runBasicBlockGamut( $text );
     585    }
     586
     587    function runBasicBlockGamut( $text ) {
     588        #
     589        # Run block gamut tranformations, without hashing HTML blocks. This is
     590        # useful when HTML blocks are known to be already hashed, like in the first
     591        # whole-document pass.
     592        #
     593        foreach ( $this->block_gamut as $method => $priority ) {
     594            $text = $this->$method( $text );
     595        }
     596
    601597        # Finally form paragraph and restore hashed blocks.
    602         $text = $this->formParagraphs($text);
     598        $text = $this->formParagraphs( $text );
    603599
    604600        return $text;
    605601    }
    606    
    607    
    608     function doHorizontalRules($text) {
     602
     603    function doHorizontalRules( $text ) {
    609604        # Do Horizontal Rules:
    610605        return preg_replace(
     
    619614                $           # End of line.
    620615            }mx',
    621             "\n".$this->hashBlock("<hr$this->empty_element_suffix")."\n",
    622             $text);
    623     }
    624 
     616            "\n" . $this->hashBlock( "<hr$this->empty_element_suffix" ) . "\n",
     617            $text );
     618    }
    625619
    626620    var $span_gamut = array(
    627     #
    628     # These are all the transformations that occur *within* block-level
    629     # tags like paragraphs, headers, and list items.
    630     #
     621        #
     622        # These are all the transformations that occur *within* block-level
     623        # tags like paragraphs, headers, and list items.
     624        #
    631625        # Process character escapes, code spans, and inline HTML
    632626        # in one shot.
    633         "parseSpan"           => -30,
    634 
     627        "parseSpan"           => - 30,
    635628        # Process anchor and image tags. Images must come first,
    636629        # because ![foo][f] looks like an anchor.
    637         "doImages"            =>  10,
    638         "doAnchors"           =>  20,
    639        
     630        "doImages"            => 10,
     631        "doAnchors"           => 20,
    640632        # Make links out of things like `<http://example.com/>`
    641633        # Must come after doAnchors, because you can use < and >
    642634        # delimiters in inline links like [this](<url>).
    643         "doAutoLinks"         =>  30,
    644         "encodeAmpsAndAngles" =>  40,
    645 
    646         "doItalicsAndBold"    =>  50,
    647         "doHardBreaks"        =>  60,
    648         );
    649 
    650     function runSpanGamut($text) {
    651     #
    652     # Run span gamut tranformations.
    653     #
    654         foreach ($this->span_gamut as $method => $priority) {
    655             $text = $this->$method($text);
     635        "doAutoLinks"         => 30,
     636        "encodeAmpsAndAngles" => 40,
     637        "doItalicsAndBold"    => 50,
     638        "doHardBreaks"        => 60,
     639    );
     640
     641    function runSpanGamut( $text ) {
     642        #
     643        # Run span gamut tranformations.
     644        #
     645        foreach ( $this->span_gamut as $method => $priority ) {
     646            $text = $this->$method( $text );
    656647        }
    657648
    658649        return $text;
    659650    }
    660    
    661    
    662     function doHardBreaks($text) {
     651
     652    function doHardBreaks( $text ) {
    663653        # Do hard breaks:
    664         return preg_replace_callback('/ {2,}\n/',
    665             array(&$this, '_doHardBreaks_callback'), $text);
    666     }
    667     function _doHardBreaks_callback($matches) {
    668         return $this->hashPart("<br$this->empty_element_suffix\n");
    669     }
    670 
    671 
    672     function doAnchors($text) {
    673     #
    674     # Turn Markdown link shortcuts into XHTML <a> tags.
    675     #
    676         if ($this->in_anchor) return $text;
     654        return preg_replace_callback( '/ {2,}\n/',
     655            array( &$this, '_doHardBreaks_callback' ), $text );
     656    }
     657
     658    function _doHardBreaks_callback( $matches ) {
     659        return $this->hashPart( "<br$this->empty_element_suffix\n" );
     660    }
     661
     662    function doAnchors( $text ) {
     663        #
     664        # Turn Markdown link shortcuts into XHTML <a> tags.
     665        #
     666        if ( $this->in_anchor ) {
     667            return $text;
     668        }
    677669        $this->in_anchor = true;
    678        
     670
    679671        #
    680672        # First, handle reference-style links: [link text] [id]
    681673        #
    682         $text = preg_replace_callback('{
     674        $text = preg_replace_callback( '{
    683675            (                   # wrap whole match in $1
    684676              \[
    685                 ('.$this->nested_brackets_re.') # link text = $2
     677                (' . $this->nested_brackets_re . ') # link text = $2
    686678              \]
    687679
     
    694686            )
    695687            }xs',
    696             array(&$this, '_doAnchors_reference_callback'), $text);
     688            array( &$this, '_doAnchors_reference_callback' ), $text );
    697689
    698690        #
    699691        # Next, inline-style links: [link text](url "optional title")
    700692        #
    701         $text = preg_replace_callback('{
     693        $text = preg_replace_callback( '{
    702694            (               # wrap whole match in $1
    703695              \[
    704                 ('.$this->nested_brackets_re.') # link text = $2
     696                (' . $this->nested_brackets_re . ') # link text = $2
    705697              \]
    706698              \(            # literal paren
     
    709701                    <(.+?)> # href = $3
    710702                |
    711                     ('.$this->nested_url_parenthesis_re.')  # href = $4
     703                    (' . $this->nested_url_parenthesis_re . ')  # href = $4
    712704                )
    713705                [ \n]*
     
    721713            )
    722714            }xs',
    723             array(&$this, '_doAnchors_inline_callback'), $text);
     715            array( &$this, '_doAnchors_inline_callback' ), $text );
    724716
    725717        #
     
    728720        # or [link text](/foo)
    729721        #
    730         $text = preg_replace_callback('{
     722        $text = preg_replace_callback( '{
    731723            (                   # wrap whole match in $1
    732724              \[
     
    735727            )
    736728            }xs',
    737             array(&$this, '_doAnchors_reference_callback'), $text);
     729            array( &$this, '_doAnchors_reference_callback' ), $text );
    738730
    739731        $this->in_anchor = false;
     732
    740733        return $text;
    741734    }
    742     function _doAnchors_reference_callback($matches) {
    743         $whole_match =  $matches[1];
    744         $link_text   =  $matches[2];
     735
     736    function _doAnchors_reference_callback( $matches ) {
     737        $whole_match = $matches[1];
     738        $link_text   = $matches[2];
    745739        $link_id     =& $matches[3];
    746740
    747         if ($link_id == "") {
     741        if ( $link_id == "" ) {
    748742            # for shortcut links like [this][] or [this].
    749743            $link_id = $link_text;
    750744        }
    751        
     745
    752746        # lower-case and turn embedded newlines into spaces
    753         $link_id = strtolower($link_id);
    754         $link_id = preg_replace('{[ ]?\n}', ' ', $link_id);
    755 
    756         if (isset($this->urls[$link_id])) {
    757             $url = $this->urls[$link_id];
    758             $url = $this->encodeAttribute($url);
    759            
     747        $link_id = strtolower( $link_id );
     748        $link_id = preg_replace( '{[ ]?\n}', ' ', $link_id );
     749
     750        if ( isset( $this->urls[ $link_id ] ) ) {
     751            $url = $this->urls[ $link_id ];
     752            $url = $this->encodeAttribute( $url );
     753
    760754            $result = "<a href=\"$url\"";
    761             if ( isset( $this->titles[$link_id] ) ) {
    762                 $title = $this->titles[$link_id];
    763                 $title = $this->encodeAttribute($title);
    764                 $result .=  " title=\"$title\"";
    765             }
    766        
    767             $link_text = $this->runSpanGamut($link_text);
     755            if ( isset( $this->titles[ $link_id ] ) ) {
     756                $title = $this->titles[ $link_id ];
     757                $title = $this->encodeAttribute( $title );
     758                $result .= " title=\"$title\"";
     759            }
     760
     761            $link_text = $this->runSpanGamut( $link_text );
    768762            $result .= ">$link_text</a>";
    769             $result = $this->hashPart($result);
    770         }
    771         else {
     763            $result = $this->hashPart( $result );
     764        } else {
    772765            $result = $whole_match;
    773766        }
     767
    774768        return $result;
    775769    }
    776     function _doAnchors_inline_callback($matches) {
    777         $whole_match    =  $matches[1];
    778         $link_text      =  $this->runSpanGamut($matches[2]);
    779         $url            =  $matches[3] == '' ? $matches[4] : $matches[3];
    780         $title          =& $matches[7];
    781 
    782         $url = $this->encodeAttribute($url);
     770
     771    function _doAnchors_inline_callback( $matches ) {
     772        $whole_match = $matches[1];
     773        $link_text   = $this->runSpanGamut( $matches[2] );
     774        $url         = $matches[3] == '' ? $matches[4] : $matches[3];
     775        $title       =& $matches[7];
     776
     777        $url = $this->encodeAttribute( $url );
    783778
    784779        $result = "<a href=\"$url\"";
    785         if (isset($title)) {
    786             $title = $this->encodeAttribute($title);
    787             $result .=  " title=\"$title\"";
    788         }
    789        
    790         $link_text = $this->runSpanGamut($link_text);
     780        if ( isset( $title ) ) {
     781            $title = $this->encodeAttribute( $title );
     782            $result .= " title=\"$title\"";
     783        }
     784
     785        $link_text = $this->runSpanGamut( $link_text );
    791786        $result .= ">$link_text</a>";
    792787
    793         return $this->hashPart($result);
    794     }
    795 
    796 
    797     function doImages($text) {
    798     #
    799     # Turn Markdown image shortcuts into <img> tags.
    800     #
     788        return $this->hashPart( $result );
     789    }
     790
     791    function doImages( $text ) {
     792        #
     793        # Turn Markdown image shortcuts into <img> tags.
     794        #
    801795        #
    802796        # First, handle reference-style labeled images: ![alt text][id]
    803797        #
    804         $text = preg_replace_callback('{
     798        $text = preg_replace_callback( '{
    805799            (               # wrap whole match in $1
    806800              !\[
    807                 ('.$this->nested_brackets_re.')     # alt text = $2
     801                (' . $this->nested_brackets_re . ')     # alt text = $2
    808802              \]
    809803
     
    816810
    817811            )
    818             }xs', 
    819             array(&$this, '_doImages_reference_callback'), $text);
     812            }xs',
     813            array( &$this, '_doImages_reference_callback' ), $text );
    820814
    821815        #
     
    823817        # Don't forget: encode * and _
    824818        #
    825         $text = preg_replace_callback('{
     819        $text = preg_replace_callback( '{
    826820            (               # wrap whole match in $1
    827821              !\[
    828                 ('.$this->nested_brackets_re.')     # alt text = $2
     822                (' . $this->nested_brackets_re . ')     # alt text = $2
    829823              \]
    830824              \s?           # One optional whitespace character
     
    834828                    <(\S*)> # src url = $3
    835829                |
    836                     ('.$this->nested_url_parenthesis_re.')  # src url = $4
     830                    (' . $this->nested_url_parenthesis_re . ')  # src url = $4
    837831                )
    838832                [ \n]*
     
    846840            )
    847841            }xs',
    848             array(&$this, '_doImages_inline_callback'), $text);
     842            array( &$this, '_doImages_inline_callback' ), $text );
    849843
    850844        return $text;
    851845    }
    852     function _doImages_reference_callback($matches) {
     846
     847    function _doImages_reference_callback( $matches ) {
    853848        $whole_match = $matches[1];
    854849        $alt_text    = $matches[2];
    855         $link_id     = strtolower($matches[3]);
    856 
    857         if ($link_id == "") {
    858             $link_id = strtolower($alt_text); # for shortcut links like ![this][].
    859         }
    860 
    861         $alt_text = $this->encodeAttribute($alt_text);
    862         if (isset($this->urls[$link_id])) {
    863             $url = $this->encodeAttribute($this->urls[$link_id]);
     850        $link_id     = strtolower( $matches[3] );
     851
     852        if ( $link_id == "" ) {
     853            $link_id = strtolower( $alt_text ); # for shortcut links like ![this][].
     854        }
     855
     856        $alt_text = $this->encodeAttribute( $alt_text );
     857        if ( isset( $this->urls[ $link_id ] ) ) {
     858            $url    = $this->encodeAttribute( $this->urls[ $link_id ] );
    864859            $result = "<img src=\"$url\" alt=\"$alt_text\"";
    865             if (isset($this->titles[$link_id])) {
    866                 $title = $this->titles[$link_id];
    867                 $title = $this->encodeAttribute($title);
    868                 $result .=  " title=\"$title\"";
     860            if ( isset( $this->titles[ $link_id ] ) ) {
     861                $title = $this->titles[ $link_id ];
     862                $title = $this->encodeAttribute( $title );
     863                $result .= " title=\"$title\"";
    869864            }
    870865            $result .= $this->empty_element_suffix;
    871             $result = $this->hashPart($result);
    872         }
    873         else {
     866            $result = $this->hashPart( $result );
     867        } else {
    874868            # If there's no such link ID, leave intact:
    875869            $result = $whole_match;
     
    878872        return $result;
    879873    }
    880     function _doImages_inline_callback($matches) {
    881         $whole_match    = $matches[1];
    882         $alt_text       = $matches[2];
    883         $url            = $matches[3] == '' ? $matches[4] : $matches[3];
    884         $title          =& $matches[7];
    885 
    886         $alt_text = $this->encodeAttribute($alt_text);
    887         $url = $this->encodeAttribute($url);
    888         $result = "<img src=\"$url\" alt=\"$alt_text\"";
    889         if (isset($title)) {
    890             $title = $this->encodeAttribute($title);
    891             $result .=  " title=\"$title\""; # $title already quoted
     874
     875    function _doImages_inline_callback( $matches ) {
     876        $whole_match = $matches[1];
     877        $alt_text    = $matches[2];
     878        $url         = $matches[3] == '' ? $matches[4] : $matches[3];
     879        $title       =& $matches[7];
     880
     881        $alt_text = $this->encodeAttribute( $alt_text );
     882        $url      = $this->encodeAttribute( $url );
     883        $result   = "<img src=\"$url\" alt=\"$alt_text\"";
     884        if ( isset( $title ) ) {
     885            $title = $this->encodeAttribute( $title );
     886            $result .= " title=\"$title\""; # $title already quoted
    892887        }
    893888        $result .= $this->empty_element_suffix;
    894889
    895         return $this->hashPart($result);
    896     }
    897 
    898 
    899     function doHeaders($text) {
     890        return $this->hashPart( $result );
     891    }
     892
     893    function doHeaders( $text ) {
    900894        # Setext-style headers:
    901895        #     Header 1
    902896        #     ========
    903         # 
     897        #
    904898        #     Header 2
    905899        #     --------
    906900        #
    907         $text = preg_replace_callback('{ ^(.+?)[ ]*\n(=+|-+)[ ]*\n+ }mx',
    908             array(&$this, '_doHeaders_callback_setext'), $text);
     901        $text = preg_replace_callback( '{ ^(.+?)[ ]*\n(=+|-+)[ ]*\n+ }mx',
     902            array( &$this, '_doHeaders_callback_setext' ), $text );
    909903
    910904        # atx-style headers:
     
    915909        #   ###### Header 6
    916910        #
    917         $text = preg_replace_callback('{
     911        $text = preg_replace_callback( '{
    918912                ^(\#{1,6})  # $1 = string of #\'s
    919913                [ ]*
     
    923917                \n+
    924918            }xm',
    925             array(&$this, '_doHeaders_callback_atx'), $text);
     919            array( &$this, '_doHeaders_callback_atx' ), $text );
    926920
    927921        return $text;
    928922    }
    929     function _doHeaders_callback_setext($matches) {
     923
     924    function _doHeaders_callback_setext( $matches ) {
    930925        # Terrible hack to check we haven't found an empty list item.
    931         if ($matches[2] == '-' && preg_match('{^-(?: |$)}', $matches[1]))
     926        if ( $matches[2] == '-' && preg_match( '{^-(?: |$)}', $matches[1] ) ) {
    932927            return $matches[0];
    933        
     928        }
     929
    934930        $level = $matches[2]{0} == '=' ? 1 : 2;
    935         $block = "<h$level>".$this->runSpanGamut($matches[1])."</h$level>";
    936         return "\n" . $this->hashBlock($block) . "\n\n";
    937     }
    938     function _doHeaders_callback_atx($matches) {
    939         $level = strlen($matches[1]);
    940         $block = "<h$level>".$this->runSpanGamut($matches[2])."</h$level>";
    941         return "\n" . $this->hashBlock($block) . "\n\n";
    942     }
    943 
    944 
    945     function doLists($text) {
    946     #
    947     # Form HTML ordered (numbered) and unordered (bulleted) lists.
    948     #
     931        $block = "<h$level>" . $this->runSpanGamut( $matches[1] ) . "</h$level>";
     932
     933        return "\n" . $this->hashBlock( $block ) . "\n\n";
     934    }
     935
     936    function _doHeaders_callback_atx( $matches ) {
     937        $level = strlen( $matches[1] );
     938        $block = "<h$level>" . $this->runSpanGamut( $matches[2] ) . "</h$level>";
     939
     940        return "\n" . $this->hashBlock( $block ) . "\n\n";
     941    }
     942
     943    function doLists( $text ) {
     944        #
     945        # Form HTML ordered (numbered) and unordered (bulleted) lists.
     946        #
    949947        $less_than_tab = $this->tab_width - 1;
    950948
     
    957955            $marker_ul_re => $marker_ol_re,
    958956            $marker_ol_re => $marker_ul_re,
    959             );
    960 
    961         foreach ($markers_relist as $marker_re => $other_marker_re) {
     957        );
     958
     959        foreach ( $markers_relist as $marker_re => $other_marker_re ) {
    962960            # Re-usable pattern to match any entirel ul or ol list:
    963961            $whole_list_re = '
    964962                (                               # $1 = whole list
    965963                  (                             # $2
    966                     ([ ]{0,'.$less_than_tab.'}) # $3 = number of spaces
    967                     ('.$marker_re.')            # $4 = first list item marker
     964                    ([ ]{0,' . $less_than_tab . '}) # $3 = number of spaces
     965                    (' . $marker_re . ')            # $4 = first list item marker
    968966                    [ ]+
    969967                  )
     
    976974                      (?!                       # Negative lookahead for another list item marker
    977975                        [ ]*
    978                         '.$marker_re.'[ ]+
     976                        ' . $marker_re . '[ ]+
    979977                      )
    980978                    |
     
    982980                        \n
    983981                        \3                      # Must have the same indentation
    984                         '.$other_marker_re.'[ ]+
     982                        ' . $other_marker_re . '[ ]+
    985983                      )
    986984                  )
    987985                )
    988986            '; // mx
    989            
     987
    990988            # We use a different prefix before nested lists than top-level lists.
    991989            # See extended comment in _ProcessListItems().
    992        
    993             if ($this->list_level) {
    994                 $text = preg_replace_callback('{
     990
     991            if ( $this->list_level ) {
     992                $text = preg_replace_callback( '{
    995993                        ^
    996                         '.$whole_list_re.'
     994                        ' . $whole_list_re . '
    997995                    }mx',
    998                     array(&$this, '_doLists_callback'), $text);
    999             }
    1000             else {
    1001                 $text = preg_replace_callback('{
     996                    array( &$this, '_doLists_callback' ), $text );
     997            } else {
     998                $text = preg_replace_callback( '{
    1002999                        (?:(?<=\n)\n|\A\n?) # Must eat the newline
    1003                         '.$whole_list_re.'
     1000                        ' . $whole_list_re . '
    10041001                    }mx',
    1005                     array(&$this, '_doLists_callback'), $text);
     1002                    array( &$this, '_doLists_callback' ), $text );
    10061003            }
    10071004        }
     
    10091006        return $text;
    10101007    }
    1011     function _doLists_callback($matches) {
     1008
     1009    function _doLists_callback( $matches ) {
    10121010        # Re-usable patterns to match list item bullets and number markers:
    10131011        $marker_ul_re  = '[*+-]';
    10141012        $marker_ol_re  = '\d+[.]';
    10151013        $marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
    1016        
    1017         $list = $matches[1];
    1018         $list_type = preg_match("/$marker_ul_re/", $matches[4]) ? "ul" : "ol";
    1019        
     1014
     1015        $list      = $matches[1];
     1016        $list_type = preg_match( "/$marker_ul_re/", $matches[4] ) ? "ul" : "ol";
     1017
    10201018        $marker_any_re = ( $list_type == "ul" ? $marker_ul_re : $marker_ol_re );
    1021        
     1019
    10221020        $list .= "\n";
    1023         $result = $this->processListItems($list, $marker_any_re);
    1024        
    1025         $result = $this->hashBlock("<$list_type>\n" . $result . "</$list_type>");
    1026         return "\n". $result ."\n\n";
     1021        $result = $this->processListItems( $list, $marker_any_re );
     1022
     1023        $result = $this->hashBlock( "<$list_type>\n" . $result . "</$list_type>" );
     1024
     1025        return "\n" . $result . "\n\n";
    10271026    }
    10281027
    10291028    var $list_level = 0;
    10301029
    1031     function processListItems($list_str, $marker_any_re) {
    1032     #
    1033     #   Process the contents of a single ordered or unordered list, splitting it
    1034     #   into individual list items.
    1035     #
     1030    function processListItems( $list_str, $marker_any_re ) {
     1031        #
     1032        #   Process the contents of a single ordered or unordered list, splitting it
     1033        #   into individual list items.
     1034        #
    10361035        # The $this->list_level global keeps track of when we're inside a list.
    10371036        # Each time we enter a list, we increment it; when we leave a list,
     
    10541053        # change the syntax rules such that sub-lists must start with a
    10551054        # starting cardinal number; e.g. "1." or "a.".
    1056        
    1057         $this->list_level++;
     1055
     1056        $this->list_level ++;
    10581057
    10591058        # trim trailing blank lines:
    1060         $list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
    1061 
    1062         $list_str = preg_replace_callback('{
     1059        $list_str = preg_replace( "/\n{2,}\\z/", "\n", $list_str );
     1060
     1061        $list_str = preg_replace_callback( '{
    10631062            (\n)?                           # leading line = $1
    10641063            (^[ ]*)                         # leading whitespace = $2
    1065             ('.$marker_any_re.'             # list marker and space = $3
     1064            (' . $marker_any_re . '             # list marker and space = $3
    10661065                (?:[ ]+|(?=\n)) # space only required if item is not empty
    10671066            )
    10681067            ((?s:.*?))                      # list item text   = $4
    10691068            (?:(\n+(?=\n))|\n)              # tailing blank line = $5
    1070             (?= \n* (\z | \2 ('.$marker_any_re.') (?:[ ]+|(?=\n))))
     1069            (?= \n* (\z | \2 (' . $marker_any_re . ') (?:[ ]+|(?=\n))))
    10711070            }xm',
    1072             array(&$this, '_processListItems_callback'), $list_str);
    1073 
    1074         $this->list_level--;
     1071            array( &$this, '_processListItems_callback' ), $list_str );
     1072
     1073        $this->list_level --;
     1074
    10751075        return $list_str;
    10761076    }
    1077     function _processListItems_callback($matches) {
    1078         $item = $matches[4];
    1079         $leading_line =& $matches[1];
    1080         $leading_space =& $matches[2];
    1081         $marker_space = $matches[3];
     1077
     1078    function _processListItems_callback( $matches ) {
     1079        $item               = $matches[4];
     1080        $leading_line       =& $matches[1];
     1081        $leading_space      =& $matches[2];
     1082        $marker_space       = $matches[3];
    10821083        $tailing_blank_line =& $matches[5];
    10831084
    1084         if ($leading_line || $tailing_blank_line ||
    1085             preg_match('/\n{2,}/', $item))
    1086         {
     1085        if ( $leading_line || $tailing_blank_line ||
     1086             preg_match( '/\n{2,}/', $item )
     1087        ) {
    10871088            # Replace marker with the appropriate whitespace indentation
    1088             $item = $leading_space . str_repeat(' ', strlen($marker_space)) . $item;
    1089             $item = $this->runBlockGamut($this->outdent($item)."\n");
    1090         }
    1091         else {
     1089            $item = $leading_space . str_repeat( ' ', strlen( $marker_space ) ) . $item;
     1090            $item = $this->runBlockGamut( $this->outdent( $item ) . "\n" );
     1091        } else {
    10921092            # Recursion for sub-lists:
    1093             $item = $this->doLists($this->outdent($item));
    1094             $item = preg_replace('/\n+$/', '', $item);
    1095             $item = $this->runSpanGamut($item);
     1093            $item = $this->doLists( $this->outdent( $item ) );
     1094            $item = preg_replace( '/\n+$/', '', $item );
     1095            $item = $this->runSpanGamut( $item );
    10961096        }
    10971097
     
    10991099    }
    11001100
    1101 
    1102     function doCodeBlocks($text) {
    1103     #
    1104     #   Process Markdown `<pre><code>` blocks.
    1105     #
    1106         $text = preg_replace_callback('{
     1101    function doCodeBlocks( $text ) {
     1102        #
     1103        #   Process Markdown `<pre><code>` blocks.
     1104        #
     1105        $text = preg_replace_callback( '{
    11071106                (?:\n\n|\A\n?)
    11081107                (               # $1 = the code block -- one or more lines, starting with a space/tab
    11091108                  (?>
    1110                     [ ]{'.$this->tab_width.'}  # Lines must start with a tab or a tab-width of spaces
     1109                    [ ]{' . $this->tab_width . '}  # Lines must start with a tab or a tab-width of spaces
    11111110                    .*\n+
    11121111                  )+
    11131112                )
    1114                 ((?=^[ ]{0,'.$this->tab_width.'}\S)|\Z) # Lookahead for non-space at line-start, or end of doc
     1113                ((?=^[ ]{0,' . $this->tab_width . '}\S)|\Z) # Lookahead for non-space at line-start, or end of doc
    11151114            }xm',
    1116             array(&$this, '_doCodeBlocks_callback'), $text);
     1115            array( &$this, '_doCodeBlocks_callback' ), $text );
    11171116
    11181117        return $text;
    11191118    }
    1120     function _doCodeBlocks_callback($matches) {
     1119
     1120    function _doCodeBlocks_callback( $matches ) {
    11211121        $codeblock = $matches[1];
    11221122
    1123         $codeblock = $this->outdent($codeblock);
    1124         $codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
     1123        $codeblock = $this->outdent( $codeblock );
     1124        $codeblock = htmlspecialchars( $codeblock, ENT_NOQUOTES );
    11251125
    11261126        # trim leading newlines and trailing newlines
    1127         $codeblock = preg_replace('/\A\n+|\n+\z/', '', $codeblock);
     1127        $codeblock = preg_replace( '/\A\n+|\n+\z/', '', $codeblock );
    11281128
    11291129        $codeblock = "<pre><code>$codeblock\n</code></pre>";
    1130         return "\n\n".$this->hashBlock($codeblock)."\n\n";
    1131     }
    1132 
    1133 
    1134     function makeCodeSpan($code) {
    1135     #
    1136     # Create a code span markup for $code. Called from handleSpanToken.
    1137     #
    1138         $code = htmlspecialchars(trim($code), ENT_NOQUOTES);
    1139         return $this->hashPart("<code>$code</code>");
    1140     }
    1141 
     1130
     1131        return "\n\n" . $this->hashBlock( $codeblock ) . "\n\n";
     1132    }
     1133
     1134    function makeCodeSpan( $code ) {
     1135        #
     1136        # Create a code span markup for $code. Called from handleSpanToken.
     1137        #
     1138        $code = htmlspecialchars( trim( $code ), ENT_NOQUOTES );
     1139
     1140        return $this->hashPart( "<code>$code</code>" );
     1141    }
    11421142
    11431143    var $em_relist = array(
     
    11451145        '*' => '(?<=\S|^)(?<!\*)\*(?!\*)',
    11461146        '_' => '(?<=\S|^)(?<!_)_(?!_)',
    1147         );
     1147    );
    11481148    var $strong_relist = array(
    11491149        ''   => '(?:(?<!\*)\*\*(?!\*)|(?<!_)__(?!_))(?=\S|$)(?![.,:;]\s)',
    11501150        '**' => '(?<=\S|^)(?<!\*)\*\*(?!\*)',
    11511151        '__' => '(?<=\S|^)(?<!_)__(?!_)',
    1152         );
     1152    );
    11531153    var $em_strong_relist = array(
    11541154        ''    => '(?:(?<!\*)\*\*\*(?!\*)|(?<!_)___(?!_))(?=\S|$)(?![.,:;]\s)',
    11551155        '***' => '(?<=\S|^)(?<!\*)\*\*\*(?!\*)',
    11561156        '___' => '(?<=\S|^)(?<!_)___(?!_)',
    1157         );
     1157    );
    11581158    var $em_strong_prepared_relist;
    1159    
     1159
    11601160    function prepareItalicsAndBold() {
    1161     #
    1162     # Prepare regular expressions for searching emphasis tokens in any
    1163     # context.
    1164     #
    1165         foreach ($this->em_relist as $em => $em_re) {
    1166             foreach ($this->strong_relist as $strong => $strong_re) {
     1161        #
     1162        # Prepare regular expressions for searching emphasis tokens in any
     1163        # context.
     1164        #
     1165        foreach ( $this->em_relist as $em => $em_re ) {
     1166            foreach ( $this->strong_relist as $strong => $strong_re ) {
    11671167                # Construct list of allowed token expressions.
    11681168                $token_relist = array();
    1169                 if (isset($this->em_strong_relist["$em$strong"])) {
     1169                if ( isset( $this->em_strong_relist["$em$strong"] ) ) {
    11701170                    $token_relist[] = $this->em_strong_relist["$em$strong"];
    11711171                }
    11721172                $token_relist[] = $em_re;
    11731173                $token_relist[] = $strong_re;
    1174                
     1174
    11751175                # Construct master expression from list.
    1176                 $token_re = '{('. implode('|', $token_relist) .')}';
     1176                $token_re                                      = '{(' . implode( '|', $token_relist ) . ')}';
    11771177                $this->em_strong_prepared_relist["$em$strong"] = $token_re;
    11781178            }
    11791179        }
    11801180    }
    1181    
    1182     function doItalicsAndBold($text) {
    1183         $token_stack = array('');
    1184         $text_stack = array('');
    1185         $em = '';
    1186         $strong = '';
     1181
     1182    function doItalicsAndBold( $text ) {
     1183        $token_stack  = array( '' );
     1184        $text_stack   = array( '' );
     1185        $em           = '';
     1186        $strong       = '';
    11871187        $tree_char_em = false;
    1188        
    1189         while (1) {
     1188
     1189        while ( 1 ) {
    11901190            #
    11911191            # Get prepared regular expression for seraching emphasis tokens
     
    11931193            #
    11941194            $token_re = $this->em_strong_prepared_relist["$em$strong"];
    1195            
     1195
    11961196            #
    1197             # Each loop iteration search for the next emphasis token. 
     1197            # Each loop iteration search for the next emphasis token.
    11981198            # Each token is then passed to handleSpanToken.
    11991199            #
    1200             $parts = preg_split($token_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
     1200            $parts = preg_split( $token_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE );
    12011201            $text_stack[0] .= $parts[0];
    12021202            $token =& $parts[1];
    1203             $text =& $parts[2];
    1204            
    1205             if (empty($token)) {
     1203            $text  =& $parts[2];
     1204
     1205            if ( empty( $token ) ) {
    12061206                # Reached end of text span: empty stack without emitting.
    12071207                # any more emphasis.
    1208                 while ($token_stack[0]) {
    1209                     $text_stack[1] .= array_shift($token_stack);
    1210                     $text_stack[0] .= array_shift($text_stack);
     1208                while ( $token_stack[0] ) {
     1209                    $text_stack[1] .= array_shift( $token_stack );
     1210                    $text_stack[0] .= array_shift( $text_stack );
    12111211                }
    12121212                break;
    12131213            }
    1214            
    1215             $token_len = strlen($token);
    1216             if ($tree_char_em) {
     1214
     1215            $token_len = strlen( $token );
     1216            if ( $tree_char_em ) {
    12171217                # Reached closing marker while inside a three-char emphasis.
    1218                 if ($token_len == 3) {
     1218                if ( $token_len == 3 ) {
    12191219                    # Three-char closing marker, close em and strong.
    1220                     array_shift($token_stack);
    1221                     $span = array_shift($text_stack);
    1222                     $span = $this->runSpanGamut($span);
     1220                    array_shift( $token_stack );
     1221                    $span = array_shift( $text_stack );
     1222                    $span = $this->runSpanGamut( $span );
    12231223                    $span = "<strong><em>$span</em></strong>";
    1224                     $text_stack[0] .= $this->hashPart($span);
    1225                     $em = '';
     1224                    $text_stack[0] .= $this->hashPart( $span );
     1225                    $em     = '';
    12261226                    $strong = '';
    12271227                } else {
    12281228                    # Other closing marker: close one em or strong and
    12291229                    # change current token state to match the other
    1230                     $token_stack[0] = str_repeat($token{0}, 3-$token_len);
    1231                     $tag = $token_len == 2 ? "strong" : "em";
    1232                     $span = $text_stack[0];
    1233                     $span = $this->runSpanGamut($span);
    1234                     $span = "<$tag>$span</$tag>";
    1235                     $text_stack[0] = $this->hashPart($span);
    1236                     $$tag = ''; # $$tag stands for $em or $strong
     1230                    $token_stack[0] = str_repeat( $token{0}, 3 - $token_len );
     1231                    $tag            = $token_len == 2 ? "strong" : "em";
     1232                    $span           = $text_stack[0];
     1233                    $span           = $this->runSpanGamut( $span );
     1234                    $span           = "<$tag>$span</$tag>";
     1235                    $text_stack[0]  = $this->hashPart( $span );
     1236                    $$tag           = ''; # $$tag stands for $em or $strong
    12371237                }
    12381238                $tree_char_em = false;
    1239             } else if ($token_len == 3) {
    1240                 if ($em) {
     1239            } else if ( $token_len == 3 ) {
     1240                if ( $em ) {
    12411241                    # Reached closing marker for both em and strong.
    12421242                    # Closing strong marker:
    1243                     for ($i = 0; $i < 2; ++$i) {
    1244                         $shifted_token = array_shift($token_stack);
    1245                         $tag = strlen($shifted_token) == 2 ? "strong" : "em";
    1246                         $span = array_shift($text_stack);
    1247                         $span = $this->runSpanGamut($span);
    1248                         $span = "<$tag>$span</$tag>";
    1249                         $text_stack[0] .= $this->hashPart($span);
     1243                    for ( $i = 0; $i < 2; ++ $i ) {
     1244                        $shifted_token = array_shift( $token_stack );
     1245                        $tag           = strlen( $shifted_token ) == 2 ? "strong" : "em";
     1246                        $span          = array_shift( $text_stack );
     1247                        $span          = $this->runSpanGamut( $span );
     1248                        $span          = "<$tag>$span</$tag>";
     1249                        $text_stack[0] .= $this->hashPart( $span );
    12501250                        $$tag = ''; # $$tag stands for $em or $strong
    12511251                    }
    12521252                } else {
    1253                     # Reached opening three-char emphasis marker. Push on token 
     1253                    # Reached opening three-char emphasis marker. Push on token
    12541254                    # stack; will be handled by the special condition above.
    1255                     $em = $token{0};
     1255                    $em     = $token{0};
    12561256                    $strong = "$em$em";
    1257                     array_unshift($token_stack, $token);
    1258                     array_unshift($text_stack, '');
     1257                    array_unshift( $token_stack, $token );
     1258                    array_unshift( $text_stack, '' );
    12591259                    $tree_char_em = true;
    12601260                }
    1261             } else if ($token_len == 2) {
    1262                 if ($strong) {
     1261            } else if ( $token_len == 2 ) {
     1262                if ( $strong ) {
    12631263                    # Unwind any dangling emphasis marker:
    1264                     if (strlen($token_stack[0]) == 1) {
    1265                         $text_stack[1] .= array_shift($token_stack);
    1266                         $text_stack[0] .= array_shift($text_stack);
     1264                    if ( strlen( $token_stack[0] ) == 1 ) {
     1265                        $text_stack[1] .= array_shift( $token_stack );
     1266                        $text_stack[0] .= array_shift( $text_stack );
    12671267                    }
    12681268                    # Closing strong marker:
    1269                     array_shift($token_stack);
    1270                     $span = array_shift($text_stack);
    1271                     $span = $this->runSpanGamut($span);
     1269                    array_shift( $token_stack );
     1270                    $span = array_shift( $text_stack );
     1271                    $span = $this->runSpanGamut( $span );
    12721272                    $span = "<strong>$span</strong>";
    1273                     $text_stack[0] .= $this->hashPart($span);
     1273                    $text_stack[0] .= $this->hashPart( $span );
    12741274                    $strong = '';
    12751275                } else {
    1276                     array_unshift($token_stack, $token);
    1277                     array_unshift($text_stack, '');
     1276                    array_unshift( $token_stack, $token );
     1277                    array_unshift( $text_stack, '' );
    12781278                    $strong = $token;
    12791279                }
    12801280            } else {
    12811281                # Here $token_len == 1
    1282                 if ($em) {
    1283                     if (strlen($token_stack[0]) == 1) {
     1282                if ( $em ) {
     1283                    if ( strlen( $token_stack[0] ) == 1 ) {
    12841284                        # Closing emphasis marker:
    1285                         array_shift($token_stack);
    1286                         $span = array_shift($text_stack);
    1287                         $span = $this->runSpanGamut($span);
     1285                        array_shift( $token_stack );
     1286                        $span = array_shift( $text_stack );
     1287                        $span = $this->runSpanGamut( $span );
    12881288                        $span = "<em>$span</em>";
    1289                         $text_stack[0] .= $this->hashPart($span);
     1289                        $text_stack[0] .= $this->hashPart( $span );
    12901290                        $em = '';
    12911291                    } else {
     
    12931293                    }
    12941294                } else {
    1295                     array_unshift($token_stack, $token);
    1296                     array_unshift($text_stack, '');
     1295                    array_unshift( $token_stack, $token );
     1296                    array_unshift( $text_stack, '' );
    12971297                    $em = $token;
    12981298                }
    12991299            }
    13001300        }
     1301
    13011302        return $text_stack[0];
    13021303    }
    13031304
    1304 
    1305     function doBlockQuotes($text) {
    1306         $text = preg_replace_callback('/
     1305    function doBlockQuotes( $text ) {
     1306        $text = preg_replace_callback( '/
    13071307              (                             # Wrap whole match in $1
    13081308                (?>
     
    13141314              )
    13151315            /xm',
    1316             array(&$this, '_doBlockQuotes_callback'), $text);
     1316            array( &$this, '_doBlockQuotes_callback' ), $text );
    13171317
    13181318        return $text;
    13191319    }
    1320     function _doBlockQuotes_callback($matches) {
     1320
     1321    function _doBlockQuotes_callback( $matches ) {
    13211322        $bq = $matches[1];
    13221323        # trim one level of quoting - trim whitespace-only lines
    1323         $bq = preg_replace('/^[ ]*>[ ]?|^[ ]+$/m', '', $bq);
    1324         $bq = $this->runBlockGamut($bq);        # recurse
    1325 
    1326         $bq = preg_replace('/^/m', "  ", $bq);
    1327         # These leading spaces cause problem with <pre> content, 
     1324        $bq = preg_replace( '/^[ ]*>[ ]?|^[ ]+$/m', '', $bq );
     1325        $bq = $this->runBlockGamut( $bq );        # recurse
     1326
     1327        $bq = preg_replace( '/^/m', "  ", $bq );
     1328        # These leading spaces cause problem with <pre> content,
    13281329        # so we need to fix that:
    1329         $bq = preg_replace_callback('{(\s*<pre>.+?</pre>)}sx',
    1330             array(&$this, '_doBlockQuotes_callback2'), $bq);
    1331 
    1332         return "\n". $this->hashBlock("<blockquote>\n$bq\n</blockquote>")."\n\n";
    1333     }
    1334     function _doBlockQuotes_callback2($matches) {
     1330        $bq = preg_replace_callback( '{(\s*<pre>.+?</pre>)}sx',
     1331            array( &$this, '_doBlockQuotes_callback2' ), $bq );
     1332
     1333        return "\n" . $this->hashBlock( "<blockquote>\n$bq\n</blockquote>" ) . "\n\n";
     1334    }
     1335
     1336    function _doBlockQuotes_callback2( $matches ) {
    13351337        $pre = $matches[1];
    1336         $pre = preg_replace('/^  /m', '', $pre);
     1338        $pre = preg_replace( '/^  /m', '', $pre );
     1339
    13371340        return $pre;
    13381341    }
    13391342
    1340 
    1341     function formParagraphs($text) {
    1342     #
    1343     #   Params:
    1344     #       $text - string to process with html <p> tags
    1345     #
     1343    function formParagraphs( $text ) {
     1344        #
     1345        #   Params:
     1346        #       $text - string to process with html <p> tags
     1347        #
    13461348        # Strip leading and trailing lines:
    1347         $text = preg_replace('/\A\n+|\n+\z/', '', $text);
    1348 
    1349         $grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY);
     1349        $text = preg_replace( '/\A\n+|\n+\z/', '', $text );
     1350
     1351        $grafs = preg_split( '/\n{2,}/', $text, - 1, PREG_SPLIT_NO_EMPTY );
    13501352
    13511353        #
    13521354        # Wrap <p> tags and unhashify HTML blocks
    13531355        #
    1354         foreach ($grafs as $key => $value) {
    1355             if (!preg_match('/^B\x1A[0-9]+B$/', $value)) {
     1356        foreach ( $grafs as $key => $value ) {
     1357            if ( ! preg_match( '/^B\x1A[0-9]+B$/', $value ) ) {
    13561358                # Is a paragraph.
    1357                 $value = $this->runSpanGamut($value);
    1358                 $value = preg_replace('/^([ ]*)/', "<p>", $value);
     1359                $value = $this->runSpanGamut( $value );
     1360                $value = preg_replace( '/^([ ]*)/', "<p>", $value );
    13591361                $value .= "</p>";
    1360                 $grafs[$key] = $this->unhash($value);
    1361             }
    1362             else {
     1362                $grafs[ $key ] = $this->unhash( $value );
     1363            } else {
    13631364                # Is a block.
    13641365                # Modify elements of @grafs in-place...
    1365                 $graf = $value;
    1366                 $block = $this->html_hashes[$graf];
    1367                 $graf = $block;
     1366                $graf  = $value;
     1367                $block = $this->html_hashes[ $graf ];
     1368                $graf  = $block;
    13681369//              if (preg_match('{
    13691370//                  \A
     
    13901391//                  # that initialization code should be pulled into its own sub, though.
    13911392//                  $div_content = $this->hashHTMLBlocks($div_content);
    1392 //                 
     1393//
    13931394//                  # Run document gamut methods on the content.
    13941395//                  foreach ($this->document_gamut as $method => $priority) {
     
    14011402//                  $graf = $div_open . "\n" . $div_content . "\n" . $div_close;
    14021403//              }
    1403                 $grafs[$key] = $graf;
    1404             }
    1405         }
    1406 
    1407         return implode("\n\n", $grafs);
    1408     }
    1409 
    1410 
    1411     function encodeAttribute($text) {
    1412     #
    1413     # Encode text for a double-quoted HTML attribute. This function
    1414     # is *not* suitable for attributes enclosed in single quotes.
    1415     #
    1416         $text = $this->encodeAmpsAndAngles($text);
    1417         $text = str_replace('"', '&quot;', $text);
     1404                $grafs[ $key ] = $graf;
     1405            }
     1406        }
     1407
     1408        return implode( "\n\n", $grafs );
     1409    }
     1410
     1411    function encodeAttribute( $text ) {
     1412        #
     1413        # Encode text for a double-quoted HTML attribute. This function
     1414        # is *not* suitable for attributes enclosed in single quotes.
     1415        #
     1416        $text = $this->encodeAmpsAndAngles( $text );
     1417        $text = str_replace( '"', '&quot;', $text );
     1418
    14181419        return $text;
    14191420    }
    1420    
    1421    
    1422     function encodeAmpsAndAngles($text) {
    1423     #
    1424     # Smart processing for ampersands and angle brackets that need to
    1425     # be encoded. Valid character entities are left alone unless the
    1426     # no-entities mode is set.
    1427     #
    1428         if ($this->no_entities) {
    1429             $text = str_replace('&', '&amp;', $text);
     1421
     1422    function encodeAmpsAndAngles( $text ) {
     1423        #
     1424        # Smart processing for ampersands and angle brackets that need to
     1425        # be encoded. Valid character entities are left alone unless the
     1426        # no-entities mode is set.
     1427        #
     1428        if ( $this->no_entities ) {
     1429            $text = str_replace( '&', '&amp;', $text );
    14301430        } else {
    14311431            # Ampersand-encoding based entirely on Nat Irons's Amputator
    14321432            # MT plugin: <http://bumppo.net/projects/amputator/>
    1433             $text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/',
    1434                                 '&amp;', $text);;
     1433            $text = preg_replace( '/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/',
     1434                '&amp;', $text );;
    14351435        }
    14361436        # Encode remaining <'s
    1437         $text = str_replace('<', '&lt;', $text);
     1437        $text = str_replace( '<', '&lt;', $text );
    14381438
    14391439        return $text;
    14401440    }
    14411441
    1442 
    1443     function doAutoLinks($text) {
    1444         $text = preg_replace_callback('{<((https?|ftp|dict):[^\'">\s]+)>}i',
    1445             array(&$this, '_doAutoLinks_url_callback'), $text);
     1442    function doAutoLinks( $text ) {
     1443        $text = preg_replace_callback( '{<((https?|ftp|dict):[^\'">\s]+)>}i',
     1444            array( &$this, '_doAutoLinks_url_callback' ), $text );
    14461445
    14471446        # Email addresses: <address@domain.foo>
    1448         $text = preg_replace_callback('{
     1447        $text = preg_replace_callback( '{
    14491448            <
    14501449            (?:mailto:)?
     
    14641463            >
    14651464            }xi',
    1466             array(&$this, '_doAutoLinks_email_callback'), $text);
     1465            array( &$this, '_doAutoLinks_email_callback' ), $text );
    14671466
    14681467        return $text;
    14691468    }
    1470     function _doAutoLinks_url_callback($matches) {
    1471         $url = $this->encodeAttribute($matches[1]);
     1469
     1470    function _doAutoLinks_url_callback( $matches ) {
     1471        $url  = $this->encodeAttribute( $matches[1] );
    14721472        $link = "<a href=\"$url\">$url</a>";
    1473         return $this->hashPart($link);
    1474     }
    1475     function _doAutoLinks_email_callback($matches) {
     1473
     1474        return $this->hashPart( $link );
     1475    }
     1476
     1477    function _doAutoLinks_email_callback( $matches ) {
    14761478        $address = $matches[1];
    1477         $link = $this->encodeEmailAddress($address);
    1478         return $this->hashPart($link);
    1479     }
    1480 
    1481 
    1482     function encodeEmailAddress($addr) {
    1483     #
    1484     #   Input: an email address, e.g. "foo@example.com"
    1485     #
    1486     #   Output: the email address as a mailto link, with each character
    1487     #       of the address encoded as either a decimal or hex entity, in
    1488     #       the hopes of foiling most address harvesting spam bots. E.g.:
    1489     #
    1490     #     <p><a href="&#109;&#x61;&#105;&#x6c;&#116;&#x6f;&#58;&#x66;o&#111;
    1491     #        &#x40;&#101;&#x78;&#97;&#x6d;&#112;&#x6c;&#101;&#46;&#x63;&#111;
    1492     #        &#x6d;">&#x66;o&#111;&#x40;&#101;&#x78;&#97;&#x6d;&#112;&#x6c;
    1493     #        &#101;&#46;&#x63;&#111;&#x6d;</a></p>
    1494     #
    1495     #   Based by a filter by Matthew Wickline, posted to BBEdit-Talk.
    1496     #   With some optimizations by Milian Wolff.
    1497     #
    1498         $addr = "mailto:" . $addr;
    1499         $chars = preg_split('/(?<!^)(?!$)/', $addr);
    1500         $seed = (int)abs(crc32($addr) / strlen($addr)); # Deterministic seed.
    1501        
    1502         foreach ($chars as $key => $char) {
    1503             $ord = ord($char);
     1479        $link    = $this->encodeEmailAddress( $address );
     1480
     1481        return $this->hashPart( $link );
     1482    }
     1483
     1484    function encodeEmailAddress( $addr ) {
     1485        #
     1486        #   Input: an email address, e.g. "foo@example.com"
     1487        #
     1488        #   Output: the email address as a mailto link, with each character
     1489        #       of the address encoded as either a decimal or hex entity, in
     1490        #       the hopes of foiling most address harvesting spam bots. E.g.:
     1491        #
     1492        #     <p><a href="&#109;&#x61;&#105;&#x6c;&#116;&#x6f;&#58;&#x66;o&#111;
     1493        #        &#x40;&#101;&#x78;&#97;&#x6d;&#112;&#x6c;&#101;&#46;&#x63;&#111;
     1494        #        &#x6d;">&#x66;o&#111;&#x40;&#101;&#x78;&#97;&#x6d;&#112;&#x6c;
     1495        #        &#101;&#46;&#x63;&#111;&#x6d;</a></p>
     1496        #
     1497        #   Based by a filter by Matthew Wickline, posted to BBEdit-Talk.
     1498        #   With some optimizations by Milian Wolff.
     1499        #
     1500        $addr  = "mailto:" . $addr;
     1501        $chars = preg_split( '/(?<!^)(?!$)/', $addr );
     1502        $seed  = (int) abs( crc32( $addr ) / strlen( $addr ) ); # Deterministic seed.
     1503
     1504        foreach ( $chars as $key => $char ) {
     1505            $ord = ord( $char );
    15041506            # Ignore non-ascii chars.
    1505             if ($ord < 128) {
    1506                 $r = ($seed * (1 + $key)) % 100; # Pseudo-random function.
     1507            if ( $ord < 128 ) {
     1508                $r = ( $seed * ( 1 + $key ) ) % 100; # Pseudo-random function.
    15071509                # roughly 10% raw, 45% hex, 45% dec
    15081510                # '@' *must* be encoded. I insist.
    1509                 if ($r > 90 && $char != '@') /* do nothing */;
    1510                 else if ($r < 45) $chars[$key] = '&#x'.dechex($ord).';';
    1511                 else              $chars[$key] = '&#'.$ord.';';
    1512             }
    1513         }
    1514        
    1515         $addr = implode('', $chars);
    1516         $text = implode('', array_slice($chars, 7)); # text without `mailto:`
     1511                if ( $r > 90 && $char != '@' ) /* do nothing */ {
     1512                    ;
     1513                } else if ( $r < 45 ) {
     1514                    $chars[ $key ] = '&#x' . dechex( $ord ) . ';';
     1515                } else {
     1516                    $chars[ $key ] = '&#' . $ord . ';';
     1517                }
     1518            }
     1519        }
     1520
     1521        $addr = implode( '', $chars );
     1522        $text = implode( '', array_slice( $chars, 7 ) ); # text without `mailto:`
    15171523        $addr = "<a href=\"$addr\">$text</a>";
    15181524
     
    15201526    }
    15211527
    1522 
    1523     function parseSpan($str) {
    1524     #
    1525     # Take the string $str and parse it into tokens, hashing embeded HTML,
    1526     # escaped characters and handling code spans.
    1527     #
     1528    function parseSpan( $str ) {
     1529        #
     1530        # Take the string $str and parse it into tokens, hashing embeded HTML,
     1531        # escaped characters and handling code spans.
     1532        #
    15281533        $output = '';
    1529        
     1534
    15301535        $span_re = '{
    15311536                (
    1532                     \\\\'.$this->escape_chars_re.'
     1537                    \\\\' . $this->escape_chars_re . '
    15331538                |
    15341539                    (?<![`\\\\])
    15351540                    `+                      # code span marker
    1536             '.( $this->no_markup ? '' : '
     1541            ' . ( $this->no_markup ? '' : '
    15371542                |
    15381543                    <!--    .*?     -->     # comment
     
    15461551                    )?
    15471552                    >
    1548             ').'
     1553            ' ) . '
    15491554                )
    15501555                }xs';
    15511556
    1552         while (1) {
     1557        while ( 1 ) {
    15531558            #
    1554             # Each loop iteration seach for either the next tag, the next 
    1555             # openning code span marker, or the next escaped character. 
     1559            # Each loop iteration seach for either the next tag, the next
     1560            # openning code span marker, or the next escaped character.
    15561561            # Each token is then passed to handleSpanToken.
    15571562            #
    1558             $parts = preg_split($span_re, $str, 2, PREG_SPLIT_DELIM_CAPTURE);
    1559            
     1563            $parts = preg_split( $span_re, $str, 2, PREG_SPLIT_DELIM_CAPTURE );
     1564
    15601565            # Create token from text preceding tag.
    1561             if ($parts[0] != "") {
     1566            if ( $parts[0] != "" ) {
    15621567                $output .= $parts[0];
    15631568            }
    1564            
     1569
    15651570            # Check if we reach the end.
    1566             if (isset($parts[1])) {
    1567                 $output .= $this->handleSpanToken($parts[1], $parts[2]);
     1571            if ( isset( $parts[1] ) ) {
     1572                $output .= $this->handleSpanToken( $parts[1], $parts[2] );
    15681573                $str = $parts[2];
    1569             }
    1570             else {
     1574            } else {
    15711575                break;
    15721576            }
    15731577        }
    1574        
     1578
    15751579        return $output;
    15761580    }
    1577    
    1578    
    1579     function handleSpanToken($token, &$str) {
    1580     #
    1581     # Handle $token provided by parseSpan by determining its nature and
    1582     # returning the corresponding value that should replace it.
    1583     #
    1584         switch ($token{0}) {
     1581
     1582    function handleSpanToken( $token, &$str ) {
     1583        #
     1584        # Handle $token provided by parseSpan by determining its nature and
     1585        # returning the corresponding value that should replace it.
     1586        #
     1587        switch ( $token{0} ) {
    15851588            case "\\":
    1586                 return $this->hashPart("&#". ord($token{1}). ";");
     1589                return $this->hashPart( "&#" . ord( $token{1} ) . ";" );
    15871590            case "`":
    15881591                # Search for end marker in remaining text.
    1589                 if (preg_match('/^(.*?[^`])'.preg_quote($token).'(?!`)(.*)$/sm',
    1590                     $str, $matches))
    1591                 {
    1592                     $str = $matches[2];
    1593                     $codespan = $this->makeCodeSpan($matches[1]);
    1594                     return $this->hashPart($codespan);
     1592                if ( preg_match( '/^(.*?[^`])' . preg_quote( $token ) . '(?!`)(.*)$/sm',
     1593                    $str, $matches ) ) {
     1594                    $str      = $matches[2];
     1595                    $codespan = $this->makeCodeSpan( $matches[1] );
     1596
     1597                    return $this->hashPart( $codespan );
    15951598                }
     1599
    15961600                return $token; // return as text since no ending marker found.
    15971601            default:
    1598                 return $this->hashPart($token);
    1599         }
    1600     }
    1601 
    1602 
    1603     function outdent($text) {
    1604     #
    1605     # Remove one level of line-leading tabs or spaces
    1606     #
    1607         return preg_replace('/^(\t|[ ]{1,'.$this->tab_width.'})/m', '', $text);
    1608     }
    1609 
    1610 
    1611     # String length function for detab. `_initDetab` will create a function to
     1602                return $this->hashPart( $token );
     1603        }
     1604    }
     1605
     1606    function outdent( $text ) {
     1607        #
     1608        # Remove one level of line-leading tabs or spaces
     1609        #
     1610        return preg_replace( '/^(\t|[ ]{1,' . $this->tab_width . '})/m', '', $text );
     1611    }
     1612
     1613
     1614    # String length function for detab. `_initDetab` will create a function to
    16121615    # hanlde UTF-8 if the default function does not exist.
    16131616    var $utf8_strlen = 'mb_strlen';
    1614    
    1615     function detab($text) {
    1616     #
    1617     # Replace tabs with the appropriate amount of space.
    1618     #
     1617
     1618    function detab( $text ) {
     1619        #
     1620        # Replace tabs with the appropriate amount of space.
     1621        #
    16191622        # For each line we separate the line in blocks delemited by
    1620         # tab characters. Then we reconstruct every line by adding the 
     1623        # tab characters. Then we reconstruct every line by adding the
    16211624        # appropriate number of space between each blocks.
    1622        
    1623         $text = preg_replace_callback('/^.*\t.*$/m',
    1624             array(&$this, '_detab_callback'), $text);
     1625
     1626        $text = preg_replace_callback( '/^.*\t.*$/m',
     1627            array( &$this, '_detab_callback' ), $text );
    16251628
    16261629        return $text;
    16271630    }
    1628     function _detab_callback($matches) {
    1629         $line = $matches[0];
     1631
     1632    function _detab_callback( $matches ) {
     1633        $line   = $matches[0];
    16301634        $strlen = $this->utf8_strlen; # strlen function for UTF-8.
    1631        
     1635
    16321636        # Split in blocks.
    1633         $blocks = explode("\t", $line);
     1637        $blocks = explode( "\t", $line );
    16341638        # Add each blocks to the line.
    16351639        $line = $blocks[0];
    1636         unset($blocks[0]); # Do not add first block twice.
    1637         foreach ($blocks as $block) {
     1640        unset( $blocks[0] ); # Do not add first block twice.
     1641        foreach ( $blocks as $block ) {
    16381642            # Calculate amount of space, insert spaces, insert block.
    1639             $amount = $this->tab_width -
    1640                 $strlen($line, 'UTF-8') % $this->tab_width;
    1641             $line .= str_repeat(" ", $amount) . $block;
    1642         }
     1643            $amount = $this->tab_width -
     1644                      $strlen( $line, 'UTF-8' ) % $this->tab_width;
     1645            $line .= str_repeat( " ", $amount ) . $block;
     1646        }
     1647
    16431648        return $line;
    16441649    }
     1650
    16451651    function _initDetab() {
    1646     #
    1647     # Check for the availability of the function in the `utf8_strlen` property
    1648     # (initially `mb_strlen`). If the function is not available, create a
    1649     # function that will loosely count the number of UTF-8 characters with a
    1650     # regular expression.
    1651     #
    1652         if (function_exists($this->utf8_strlen)) return;
    1653         $this->utf8_strlen = create_function('$text', 'return preg_match_all(
    1654             "/[\\\\x00-\\\\xBF]|[\\\\xC0-\\\\xFF][\\\\x80-\\\\xBF]*/",
    1655             $text, $m);');
    1656     }
    1657 
    1658 
    1659     function unhash($text) {
    1660     #
    1661     # Swap back in all the tags hashed by _HashHTMLBlocks.
    1662     #
    1663         return preg_replace_callback('/(.)\x1A[0-9]+\1/',
    1664             array(&$this, '_unhash_callback'), $text);
    1665     }
    1666     function _unhash_callback($matches) {
    1667         return $this->html_hashes[$matches[0]];
    1668     }
    1669 
     1652        #
     1653        # Check for the availability of the function in the `utf8_strlen` property
     1654        # (initially `mb_strlen`). If the function is not available, create a
     1655        # function that will loosely count the number of UTF-8 characters with a
     1656        # regular expression.
     1657        #
     1658        if ( function_exists( $this->utf8_strlen ) ) {
     1659            return;
     1660        }
     1661        $this->utf8_strlen = create_function( '$text', 'return preg_match_all(
     1662            "/[\\\\x00-\\\\xBF]|[\\\\xC0-\\\\xFF][\\\\x80-\\\\xBF]*/",
     1663            $text, $m);' );
     1664    }
     1665
     1666    function unhash( $text ) {
     1667        #
     1668        # Swap back in all the tags hashed by _HashHTMLBlocks.
     1669        #
     1670        return preg_replace_callback( '/(.)\x1A[0-9]+\1/',
     1671            array( &$this, '_unhash_callback' ), $text );
     1672    }
     1673
     1674    function _unhash_callback( $matches ) {
     1675        return $this->html_hashes[ $matches[0] ];
     1676    }
    16701677}
    1671 
    16721678
    16731679#
     
    16761682
    16771683class MarkdownExtra_Parser extends Markdown_Parser {
    1678 
    16791684    # Prefix for footnote ids.
    16801685    var $fn_id_prefix = "";
    1681    
    16821686    # Optional title attribute for footnote links and backlinks.
    16831687    var $fn_link_title = MARKDOWN_FN_LINK_TITLE;
    16841688    var $fn_backlink_title = MARKDOWN_FN_BACKLINK_TITLE;
    1685    
    16861689    # Optional class attribute for footnote links and backlinks.
    16871690    var $fn_link_class = MARKDOWN_FN_LINK_CLASS;
    16881691    var $fn_backlink_class = MARKDOWN_FN_BACKLINK_CLASS;
    1689    
    16901692    # Predefined abbreviations.
    16911693    var $predef_abbr = array();
    16921694
    1693 
    16941695    function MarkdownExtra_Parser() {
    1695     #
    1696     # Constructor function. Initialize the parser object.
    1697     #
    1698         # Add extra escapable characters before parent constructor 
     1696        #
     1697        # Constructor function. Initialize the parser object.
     1698        #
     1699        # Add extra escapable characters before parent constructor
    16991700        # initialize the table.
    17001701        $this->escape_chars .= ':|';
    1701        
    1702         # Insert extra document, block, and span transformations. 
     1702
     1703        # Insert extra document, block, and span transformations.
    17031704        # Parent constructor will do the sorting.
    17041705        $this->document_gamut += array(
     
    17071708            "stripAbbreviations" => 25,
    17081709            "appendFootnotes"    => 50,
    1709             );
     1710        );
    17101711        $this->block_gamut += array(
    17111712            "doFencedCodeBlocks" => 5,
    17121713            "doTables"           => 15,
    17131714            "doDefLists"         => 45,
    1714             );
     1715        );
    17151716        $this->span_gamut += array(
    1716             "doFootnotes"        => 5,
    1717             "doAbbreviations"    => 70,
    1718             );
    1719        
     1717            "doFootnotes"     => 5,
     1718            "doAbbreviations" => 70,
     1719        );
     1720
    17201721        parent::Markdown_Parser();
    17211722    }
    1722    
    1723    
     1723
    17241724    # Extra variables used during extra transformations.
    17251725    var $footnotes = array();
     
    17271727    var $abbr_desciptions = array();
    17281728    var $abbr_word_re = '';
    1729    
    17301729    # Give the current footnote number.
    17311730    var $footnote_counter = 1;
    1732    
    1733    
     1731
    17341732    function setup() {
    1735     #
    1736     # Setting up Extra-specific variables.
    1737     #
     1733        #
     1734        # Setting up Extra-specific variables.
     1735        #
    17381736        parent::setup();
    1739        
    1740         $this->footnotes = array();
     1737
     1738        $this->footnotes         = array();
    17411739        $this->footnotes_ordered = array();
    1742         $this->abbr_desciptions = array();
    1743         $this->abbr_word_re = '';
    1744         $this->footnote_counter = 1;
    1745        
    1746         foreach ($this->predef_abbr as $abbr_word => $abbr_desc) {
    1747             if ($this->abbr_word_re)
     1740        $this->abbr_desciptions  = array();
     1741        $this->abbr_word_re      = '';
     1742        $this->footnote_counter  = 1;
     1743
     1744        foreach ( $this->predef_abbr as $abbr_word => $abbr_desc ) {
     1745            if ( $this->abbr_word_re ) {
    17481746                $this->abbr_word_re .= '|';
    1749             $this->abbr_word_re .= preg_quote($abbr_word);
    1750             $this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
    1751         }
    1752     }
    1753    
     1747            }
     1748            $this->abbr_word_re .= preg_quote( $abbr_word );
     1749            $this->abbr_desciptions[ $abbr_word ] = trim( $abbr_desc );
     1750        }
     1751    }
     1752
    17541753    function teardown() {
    1755     #
    1756     # Clearing Extra-specific variables.
    1757     #
    1758         $this->footnotes = array();
     1754        #
     1755        # Clearing Extra-specific variables.
     1756        #
     1757        $this->footnotes         = array();
    17591758        $this->footnotes_ordered = array();
    1760         $this->abbr_desciptions = array();
    1761         $this->abbr_word_re = '';
    1762        
     1759        $this->abbr_desciptions  = array();
     1760        $this->abbr_word_re      = '';
     1761
    17631762        parent::teardown();
    17641763    }
    1765    
    1766    
     1764
     1765
    17671766    ### HTML Block Parser ###
    1768    
     1767
    17691768    # Tags that are always treated as block tags:
    17701769    var $block_tags_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|form|fieldset|iframe|hr|legend';
    1771    
    17721770    # Tags treated as block tags only if the opening tag is alone on it's line:
    17731771    var $context_block_tags_re = 'script|noscript|math|ins|del';
    1774    
    17751772    # Tags where markdown="1" default to span mode:
    17761773    var $contain_span_tags_re = 'p|h[1-6]|li|dd|dt|td|th|legend|address';
    1777    
    1778     # Tags which must not have their contents modified, no matter where
     1774    # Tags which must not have their contents modified, no matter where
    17791775    # they appear:
    17801776    var $clean_tags_re = 'script|math';
    1781    
    17821777    # Tags that do not need to be closed.
    17831778    var $auto_close_tags_re = 'hr|img';
    1784    
    1785 
    1786     function hashHTMLBlocks($text) {
    1787     #
    1788     # Hashify HTML Blocks and "clean tags".
    1789     #
    1790     # We only want to do this for block-level HTML tags, such as headers,
    1791     # lists, and tables. That's because we still want to wrap <p>s around
    1792     # "paragraphs" that are wrapped in non-block-level tags, such as anchors,
    1793     # phrase emphasis, and spans. The list of tags we're looking for is
    1794     # hard-coded.
    1795     #
    1796     # This works by calling _HashHTMLBlocks_InMarkdown, which then calls
    1797     # _HashHTMLBlocks_InHTML when it encounter block tags. When the markdown="1"
    1798     # attribute is found whitin a tag, _HashHTMLBlocks_InHTML calls back
    1799     #  _HashHTMLBlocks_InMarkdown to handle the Markdown syntax within the tag.
    1800     # These two functions are calling each other. It's recursive!
    1801     #
     1779
     1780    function hashHTMLBlocks( $text ) {
     1781        #
     1782        # Hashify HTML Blocks and "clean tags".
     1783        #
     1784        # We only want to do this for block-level HTML tags, such as headers,
     1785        # lists, and tables. That's because we still want to wrap <p>s around
     1786        # "paragraphs" that are wrapped in non-block-level tags, such as anchors,
     1787        # phrase emphasis, and spans. The list of tags we're looking for is
     1788        # hard-coded.
     1789        #
     1790        # This works by calling _HashHTMLBlocks_InMarkdown, which then calls
     1791        # _HashHTMLBlocks_InHTML when it encounter block tags. When the markdown="1"
     1792        # attribute is found whitin a tag, _HashHTMLBlocks_InHTML calls back
     1793        #  _HashHTMLBlocks_InMarkdown to handle the Markdown syntax within the tag.
     1794        # These two functions are calling each other. It's recursive!
     1795        #
    18021796        #
    18031797        # Call the HTML-in-Markdown hasher.
    18041798        #
    1805         list($text, ) = $this->_hashHTMLBlocks_inMarkdown($text);
    1806        
     1799        list( $text, ) = $this->_hashHTMLBlocks_inMarkdown( $text );
     1800
    18071801        return $text;
    18081802    }
    1809     function _hashHTMLBlocks_inMarkdown($text, $indent = 0,
    1810                                         $enclosing_tag_re = '', $span = false)
    1811     {
    1812     #
    1813     # Parse markdown text, calling _HashHTMLBlocks_InHTML for block tags.
    1814     #
    1815     # *   $indent is the number of space to be ignored when checking for code
    1816     #     blocks. This is important because if we don't take the indent into
    1817     #     account, something like this (which looks right) won't work as expected:
    1818     #
    1819     #     <div>
    1820     #         <div markdown="1">
    1821     #         Hello World.  <-- Is this a Markdown code block or text?
    1822     #         </div>  <-- Is this a Markdown code block or a real tag?
    1823     #     <div>
    1824     #
    1825     #     If you don't like this, just don't indent the tag on which
    1826     #     you apply the markdown="1" attribute.
    1827     #
    1828     # *   If $enclosing_tag_re is not empty, stops at the first unmatched closing
    1829     #     tag with that name. Nested tags supported.
    1830     #
    1831     # *   If $span is true, text inside must treated as span. So any double
    1832     #     newline will be replaced by a single newline so that it does not create
    1833     #     paragraphs.
    1834     #
    1835     # Returns an array of that form: ( processed text , remaining text )
    1836     #
    1837         if ($text === '') return array('', '');
     1803
     1804    function _hashHTMLBlocks_inMarkdown( $text, $indent = 0, $enclosing_tag_re = '', $span = false ) {
     1805        #
     1806        # Parse markdown text, calling _HashHTMLBlocks_InHTML for block tags.
     1807        #
     1808        # *   $indent is the number of space to be ignored when checking for code
     1809        #     blocks. This is important because if we don't take the indent into
     1810        #     account, something like this (which looks right) won't work as expected:
     1811        #
     1812        #     <div>
     1813        #         <div markdown="1">
     1814        #         Hello World.  <-- Is this a Markdown code block or text?
     1815        #         </div>  <-- Is this a Markdown code block or a real tag?
     1816        #     <div>
     1817        #
     1818        #     If you don't like this, just don't indent the tag on which
     1819        #     you apply the markdown="1" attribute.
     1820        #
     1821        # *   If $enclosing_tag_re is not empty, stops at the first unmatched closing
     1822        #     tag with that name. Nested tags supported.
     1823        #
     1824        # *   If $span is true, text inside must treated as span. So any double
     1825        #     newline will be replaced by a single newline so that it does not create
     1826        #     paragraphs.
     1827        #
     1828        # Returns an array of that form: ( processed text , remaining text )
     1829        #
     1830        if ( $text === '' ) {
     1831            return array( '', '' );
     1832        }
    18381833
    18391834        # Regex to check for the presense of newlines around a block tag.
    18401835        $newline_before_re = '/(?:^\n?|\n\n)*$/';
    1841         $newline_after_re =
     1836        $newline_after_re  =
    18421837            '{
    18431838                ^                       # Start of text following the tag.
     
    18451840                [ ]*\n                  # Must be followed by newline.
    18461841            }xs';
    1847        
     1842
    18481843        # Regex to match any tag.
    18491844        $block_tag_re =
     
    18521847                    </?                 # Any opening or closing tag.
    18531848                        (?>             # Tag name.
    1854                             '.$this->block_tags_re.'            |
    1855                             '.$this->context_block_tags_re.'    |
    1856                             '.$this->clean_tags_re.'            |
    1857                             (?!\s)'.$enclosing_tag_re.'
     1849                            ' . $this->block_tags_re . '            |
     1850                            ' . $this->context_block_tags_re . '    |
     1851                            ' . $this->clean_tags_re . '            |
     1852                            (?!\s)' . $enclosing_tag_re . '
    18581853                        )
    18591854                        (?:
     
    18751870                    # Code span marker
    18761871                    `+
    1877                 '. ( !$span ? ' # If not in span.
     1872                ' . ( ! $span ? ' # If not in span.
    18781873                |
    18791874                    # Indented code block
    18801875                    (?: ^[ ]*\n | ^ | \n[ ]*\n )
    1881                     [ ]{'.($indent+4).'}[^\n]* \n
     1876                    [ ]{' . ( $indent + 4 ) . '}[^\n]* \n
    18821877                    (?>
    1883                         (?: [ ]{'.($indent+4).'}[^\n]* | [ ]* ) \n
     1878                        (?: [ ]{' . ( $indent + 4 ) . '}[^\n]* | [ ]* ) \n
    18841879                    )*
    18851880                |
    18861881                    # Fenced code block marker
    18871882                    (?> ^ | \n )
    1888                     [ ]{'.($indent).'}~~~+[ ]*\n
    1889                 ' : '' ). ' # End (if not is span).
     1883                    [ ]{' . ( $indent ) . '}~~~+[ ]*\n
     1884                ' : '' ) . ' # End (if not is span).
    18901885                )
    18911886            }xs';
    18921887
    1893        
    1894         $depth = 0;     # Current depth inside the tag tree.
    1895         $parsed = "";   # Parsed text that will be returned.
     1888        $depth  = 0;        # Current depth inside the tag tree.
     1889        $parsed = "";    # Parsed text that will be returned.
    18961890
    18971891        #
     
    19031897            # Split the text using the first $tag_match pattern found.
    19041898            # Text before  pattern will be first in the array, text after
    1905             # pattern will be at the end, and between will be any catches made 
     1899            # pattern will be at the end, and between will be any catches made
    19061900            # by the pattern.
    19071901            #
    1908             $parts = preg_split($block_tag_re, $text, 2,
    1909                                 PREG_SPLIT_DELIM_CAPTURE);
    1910            
    1911             # If in Markdown span mode, add a empty-string span-level hash 
     1902            $parts = preg_split( $block_tag_re, $text, 2,
     1903                PREG_SPLIT_DELIM_CAPTURE );
     1904
     1905            # If in Markdown span mode, add a empty-string span-level hash
    19121906            # after each newline to prevent triggering any block element.
    1913             if ($span) {
    1914                 $void = $this->hashPart("", ':');
    1915                 $newline = "$void\n";
    1916                 $parts[0] = $void . str_replace("\n", $newline, $parts[0]) . $void;
    1917             }
    1918            
     1907            if ( $span ) {
     1908                $void     = $this->hashPart( "", ':' );
     1909                $newline  = "$void\n";
     1910                $parts[0] = $void . str_replace( "\n", $newline, $parts[0] ) . $void;
     1911            }
     1912
    19191913            $parsed .= $parts[0]; # Text before current tag.
    1920            
     1914
    19211915            # If end of $text has been reached. Stop loop.
    1922             if (count($parts) < 3) {
     1916            if ( count( $parts ) < 3 ) {
    19231917                $text = "";
    19241918                break;
    19251919            }
    1926            
    1927             $tag  = $parts[1]; # Tag to handle.
    1928             $text = $parts[2]; # Remaining text after current tag.
    1929             $tag_re = preg_quote($tag); # For use in a regular expression.
    1930            
     1920
     1921            $tag    = $parts[1]; # Tag to handle.
     1922            $text   = $parts[2]; # Remaining text after current tag.
     1923            $tag_re = preg_quote( $tag ); # For use in a regular expression.
     1924
    19311925            #
    19321926            # Check for: Code span marker
    19331927            #
    1934             if ($tag{0} == "`") {
     1928            if ( $tag{0} == "`" ) {
    19351929                # Find corresponding end marker.
    1936                 $tag_re = preg_quote($tag);
    1937                 if (preg_match('{^(?>.+?|\n(?!\n))*?(?<!`)'.$tag_re.'(?!`)}',
    1938                     $text, $matches))
    1939                 {
     1930                $tag_re = preg_quote( $tag );
     1931                if ( preg_match( '{^(?>.+?|\n(?!\n))*?(?<!`)' . $tag_re . '(?!`)}',
     1932                    $text, $matches ) ) {
    19401933                    # End marker found: pass text unchanged until marker.
    19411934                    $parsed .= $tag . $matches[0];
    1942                     $text = substr($text, strlen($matches[0]));
    1943                 }
    1944                 else {
     1935                    $text = substr( $text, strlen( $matches[0] ) );
     1936                } else {
    19451937                    # Unmatched marker: just skip it.
    19461938                    $parsed .= $tag;
     
    19501942            # Check for: Indented code block.
    19511943            #
    1952             else if ($tag{0} == "\n" || $tag{0} == " ") {
    1953                 # Indented code block: pass it unchanged, will be handled 
     1944            else if ( $tag{0} == "\n" || $tag{0} == " " ) {
     1945                # Indented code block: pass it unchanged, will be handled
    19541946                # later.
    19551947                $parsed .= $tag;
     
    19581950            # Check for: Fenced code block marker.
    19591951            #
    1960             else if ($tag{0} == "~") {
     1952            else if ( $tag{0} == "~" ) {
    19611953                # Fenced code block marker: find matching end marker.
    1962                 $tag_re = preg_quote(trim($tag));
    1963                 if (preg_match('{^(?>.*\n)+?'.$tag_re.' *\n}', $text,
    1964                     $matches))
    1965                 {
     1954                $tag_re = preg_quote( trim( $tag ) );
     1955                if ( preg_match( '{^(?>.*\n)+?' . $tag_re . ' *\n}', $text,
     1956                    $matches ) ) {
    19661957                    # End marker found: pass text unchanged until marker.
    19671958                    $parsed .= $tag . $matches[0];
    1968                     $text = substr($text, strlen($matches[0]));
    1969                 }
    1970                 else {
     1959                    $text = substr( $text, strlen( $matches[0] ) );
     1960                } else {
    19711961                    # No end marker: just skip it.
    19721962                    $parsed .= $tag;
     
    19751965            #
    19761966            # Check for: Opening Block level tag or
    1977             #            Opening Context Block tag (like ins and del) 
     1967            #            Opening Context Block tag (like ins and del)
    19781968            #               used as a block tag (tag is alone on it's line).
    19791969            #
    1980             else if (preg_match('{^<(?:'.$this->block_tags_re.')\b}', $tag) ||
    1981                 (   preg_match('{^<(?:'.$this->context_block_tags_re.')\b}', $tag) &&
    1982                     preg_match($newline_before_re, $parsed) &&
    1983                     preg_match($newline_after_re, $text)    )
    1984                 )
    1985             {
     1970            else if ( preg_match( '{^<(?:' . $this->block_tags_re . ')\b}', $tag ) ||
     1971                      ( preg_match( '{^<(?:' . $this->context_block_tags_re . ')\b}', $tag ) &&
     1972                        preg_match( $newline_before_re, $parsed ) &&
     1973                        preg_match( $newline_after_re, $text ) )
     1974            ) {
    19861975                # Need to parse tag and following text using the HTML parser.
    1987                 list($block_text, $text) =
    1988                     $this->_hashHTMLBlocks_inHTML($tag . $text, "hashBlock", true);
    1989                
     1976                list( $block_text, $text ) =
     1977                    $this->_hashHTMLBlocks_inHTML( $tag . $text, "hashBlock", true );
     1978
    19901979                # Make sure it stays outside of any paragraph by adding newlines.
    19911980                $parsed .= "\n\n$block_text\n\n";
     
    19951984            #            HTML Comments, processing instructions.
    19961985            #
    1997             else if (preg_match('{^<(?:'.$this->clean_tags_re.')\b}', $tag) ||
    1998                 $tag{1} == '!' || $tag{1} == '?')
    1999             {
     1986            else if ( preg_match( '{^<(?:' . $this->clean_tags_re . ')\b}', $tag ) ||
     1987                      $tag{1} == '!' || $tag{1} == '?'
     1988            ) {
    20001989                # Need to parse tag and following text using the HTML parser.
    20011990                # (don't check for markdown attribute)
    2002                 list($block_text, $text) =
    2003                     $this->_hashHTMLBlocks_inHTML($tag . $text, "hashClean", false);
    2004                
     1991                list( $block_text, $text ) =
     1992                    $this->_hashHTMLBlocks_inHTML( $tag . $text, "hashClean", false );
     1993
    20051994                $parsed .= $block_text;
    20061995            }
     
    20081997            # Check for: Tag with same name as enclosing tag.
    20091998            #
    2010             else if ($enclosing_tag_re !== '' &&
    2011                 # Same name as enclosing tag.
    2012                 preg_match('{^</?(?:'.$enclosing_tag_re.')\b}', $tag))
    2013             {
     1999            else if ( $enclosing_tag_re !== '' &&
     2000                      # Same name as enclosing tag.
     2001                      preg_match( '{^</?(?:' . $enclosing_tag_re . ')\b}', $tag )
     2002            ) {
    20142003                #
    20152004                # Increase/decrease nested tag count.
    20162005                #
    2017                 if ($tag{1} == '/')                     $depth--;
    2018                 else if ($tag{strlen($tag)-2} != '/')   $depth++;
    2019 
    2020                 if ($depth < 0) {
     2006                if ( $tag{1} == '/' ) {
     2007                    $depth --;
     2008                } else if ( $tag{strlen( $tag ) - 2} != '/' ) {
     2009                    $depth ++;
     2010                }
     2011
     2012                if ( $depth < 0 ) {
    20212013                    #
    20222014                    # Going out of parent element. Clean up and break so we
     
    20262018                    break;
    20272019                }
    2028                
     2020
    20292021                $parsed .= $tag;
    2030             }
    2031             else {
     2022            } else {
    20322023                $parsed .= $tag;
    20332024            }
    2034         } while ($depth >= 0);
    2035        
    2036         return array($parsed, $text);
    2037     }
    2038     function _hashHTMLBlocks_inHTML($text, $hash_method, $md_attr) {
    2039     #
    2040     # Parse HTML, calling _HashHTMLBlocks_InMarkdown for block tags.
    2041     #
    2042     # *   Calls $hash_method to convert any blocks.
    2043     # *   Stops when the first opening tag closes.
    2044     # *   $md_attr indicate if the use of the `markdown="1"` attribute is allowed.
    2045     #     (it is not inside clean tags)
    2046     #
    2047     # Returns an array of that form: ( processed text , remaining text )
    2048     #
    2049         if ($text === '') return array('', '');
    2050        
     2025        } while ( $depth >= 0 );
     2026
     2027        return array( $parsed, $text );
     2028    }
     2029
     2030    function _hashHTMLBlocks_inHTML( $text, $hash_method, $md_attr ) {
     2031        #
     2032        # Parse HTML, calling _HashHTMLBlocks_InMarkdown for block tags.
     2033        #
     2034        # *   Calls $hash_method to convert any blocks.
     2035        # *   Stops when the first opening tag closes.
     2036        # *   $md_attr indicate if the use of the `markdown="1"` attribute is allowed.
     2037        #     (it is not inside clean tags)
     2038        #
     2039        # Returns an array of that form: ( processed text , remaining text )
     2040        #
     2041        if ( $text === '' ) {
     2042            return array( '', '' );
     2043        }
     2044
    20512045        # Regex to match `markdown` attribute inside of a tag.
    20522046        $markdown_attr_re = '
     
    20562050                \s*=\s*
    20572051                (?>
    2058                     (["\'])     # $1: quote delimiter       
     2052                    (["\'])     # $1: quote delimiter
    20592053                    (.*?)       # $2: attribute value
    2060                     \1          # matching delimiter   
     2054                    \1          # matching delimiter
    20612055                |
    20622056                    ([^\s>]*)   # $3: unquoted attribute value
     
    20642058                ()              # $4: make $3 always defined (avoid warnings)
    20652059            }xs';
    2066        
     2060
    20672061        # Regex to match any tag.
    20682062        $tag_re = '{
     
    20872081                )
    20882082            }xs';
    2089        
    2090         $original_text = $text;     # Save original text in case of faliure.
    2091        
    2092         $depth      = 0;    # Current depth inside the tag tree.
    2093         $block_text = "";   # Temporary text holder for current text.
    2094         $parsed     = "";   # Parsed text that will be returned.
     2083
     2084        $original_text = $text;        # Save original text in case of faliure.
     2085
     2086        $depth      = 0;    # Current depth inside the tag tree.
     2087        $block_text = "";    # Temporary text holder for current text.
     2088        $parsed     = "";    # Parsed text that will be returned.
    20952089
    20962090        #
     
    20982092        # (This pattern makes $base_tag_name_re safe without quoting.)
    20992093        #
    2100         if (preg_match('/^<([\w:$]*)\b/', $text, $matches))
     2094        if ( preg_match( '/^<([\w:$]*)\b/', $text, $matches ) ) {
    21012095            $base_tag_name_re = $matches[1];
     2096        }
    21022097
    21032098        #
     
    21082103            # Split the text using the first $tag_match pattern found.
    21092104            # Text before  pattern will be first in the array, text after
    2110             # pattern will be at the end, and between will be any catches made 
     2105            # pattern will be at the end, and between will be any catches made
    21112106            # by the pattern.
    21122107            #
    2113             $parts = preg_split($tag_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
    2114            
    2115             if (count($parts) < 3) {
     2108            $parts = preg_split( $tag_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE );
     2109
     2110            if ( count( $parts ) < 3 ) {
    21162111                #
    21172112                # End of $text reached with unbalenced tag(s).
    21182113                # In that case, we return original text unchanged and pass the
    2119                 # first character as filtered to prevent an infinite loop in the 
     2114                # first character as filtered to prevent an infinite loop in the
    21202115                # parent function.
    21212116                #
    2122                 return array($original_text{0}, substr($original_text, 1));
    2123             }
    2124            
     2117                return array( $original_text{0}, substr( $original_text, 1 ) );
     2118            }
     2119
    21252120            $block_text .= $parts[0]; # Text before current tag.
    2126             $tag         = $parts[1]; # Tag to handle.
    2127             $text        = $parts[2]; # Remaining text after current tag.
    2128            
     2121            $tag  = $parts[1]; # Tag to handle.
     2122            $text = $parts[2]; # Remaining text after current tag.
     2123
    21292124            #
    21302125            # Check for: Auto-close tag (like <hr/>)
    21312126            #            Comments and Processing Instructions.
    21322127            #
    2133             if (preg_match('{^</?(?:'.$this->auto_close_tags_re.')\b}', $tag) ||
    2134                 $tag{1} == '!' || $tag{1} == '?')
    2135             {
     2128            if ( preg_match( '{^</?(?:' . $this->auto_close_tags_re . ')\b}', $tag ) ||
     2129                 $tag{1} == '!' || $tag{1} == '?'
     2130            ) {
    21362131                # Just add the tag to the block as if it was text.
    21372132                $block_text .= $tag;
    2138             }
    2139             else {
     2133            } else {
    21402134                #
    21412135                # Increase/decrease nested tag count. Only do so if
    21422136                # the tag's name match base tag's.
    21432137                #
    2144                 if (preg_match('{^</?'.$base_tag_name_re.'\b}', $tag)) {
    2145                     if ($tag{1} == '/')                     $depth--;
    2146                     else if ($tag{strlen($tag)-2} != '/')   $depth++;
     2138                if ( preg_match( '{^</?' . $base_tag_name_re . '\b}', $tag ) ) {
     2139                    if ( $tag{1} == '/' ) {
     2140                        $depth --;
     2141                    } else if ( $tag{strlen( $tag ) - 2} != '/' ) {
     2142                        $depth ++;
     2143                    }
    21472144                }
    2148                
     2145
    21492146                #
    21502147                # Check for `markdown="1"` attribute and handle it.
    21512148                #
    2152                 if ($md_attr &&
    2153                     preg_match($markdown_attr_re, $tag, $attr_m) &&
    2154                     preg_match('/^1|block|span$/', $attr_m[2] . $attr_m[3]))
    2155                 {
     2149                if ( $md_attr &&
     2150                     preg_match( $markdown_attr_re, $tag, $attr_m ) &&
     2151                     preg_match( '/^1|block|span$/', $attr_m[2] . $attr_m[3] )
     2152                ) {
    21562153                    # Remove `markdown` attribute from opening tag.
    2157                     $tag = preg_replace($markdown_attr_re, '', $tag);
    2158                    
     2154                    $tag = preg_replace( $markdown_attr_re, '', $tag );
     2155
    21592156                    # Check if text inside this tag must be parsed in span mode.
    21602157                    $this->mode = $attr_m[2] . $attr_m[3];
    2161                     $span_mode = $this->mode == 'span' || $this->mode != 'block' &&
    2162                         preg_match('{^<(?:'.$this->contain_span_tags_re.')\b}', $tag);
    2163                    
     2158                    $span_mode  = $this->mode == 'span' || $this->mode != 'block' &&
     2159                                                           preg_match( '{^<(?:' . $this->contain_span_tags_re . ')\b}', $tag );
     2160
    21642161                    # Calculate indent before tag.
    2165                     if (preg_match('/(?:^|\n)( *?)(?! ).*?$/', $block_text, $matches)) {
     2162                    if ( preg_match( '/(?:^|\n)( *?)(?! ).*?$/', $block_text, $matches ) ) {
    21662163                        $strlen = $this->utf8_strlen;
    2167                         $indent = $strlen($matches[1], 'UTF-8');
     2164                        $indent = $strlen( $matches[1], 'UTF-8' );
    21682165                    } else {
    21692166                        $indent = 0;
    21702167                    }
    2171                    
     2168
    21722169                    # End preceding block with this tag.
    21732170                    $block_text .= $tag;
    2174                     $parsed .= $this->$hash_method($block_text);
    2175                    
     2171                    $parsed .= $this->$hash_method( $block_text );
     2172
    21762173                    # Get enclosing tag name for the ParseMarkdown function.
    21772174                    # (This pattern makes $tag_name_re safe without quoting.)
    2178                     preg_match('/^<([\w:$]*)\b/', $tag, $matches);
     2175                    preg_match( '/^<([\w:$]*)\b/', $tag, $matches );
    21792176                    $tag_name_re = $matches[1];
    2180                    
     2177
    21812178                    # Parse the content using the HTML-in-Markdown parser.
    2182                     list ($block_text, $text)
    2183                         = $this->_hashHTMLBlocks_inMarkdown($text, $indent,
    2184                             $tag_name_re, $span_mode);
    2185                    
     2179                    list ( $block_text, $text )
     2180                        = $this->_hashHTMLBlocks_inMarkdown( $text, $indent,
     2181                        $tag_name_re, $span_mode );
     2182
    21862183                    # Outdent markdown text.
    2187                     if ($indent > 0) {
    2188                         $block_text = preg_replace("/^[ ]{1,$indent}/m", "",
    2189                                                     $block_text);
     2184                    if ( $indent > 0 ) {
     2185                        $block_text = preg_replace( "/^[ ]{1,$indent}/m", "",
     2186                            $block_text );
    21902187                    }
    2191                    
     2188
    21922189                    # Append tag content to parsed text.
    2193                     if (!$span_mode)    $parsed .= "\n\n$block_text\n\n";
    2194                     else                $parsed .= "$block_text";
    2195                    
     2190                    if ( ! $span_mode ) {
     2191                        $parsed .= "\n\n$block_text\n\n";
     2192                    } else {
     2193                        $parsed .= "$block_text";
     2194                    }
     2195
    21962196                    # Start over a new block.
    21972197                    $block_text = "";
     2198                } else {
     2199                    $block_text .= $tag;
    21982200                }
    2199                 else $block_text .= $tag;
    2200             }
    2201            
    2202         } while ($depth > 0);
    2203        
     2201            }
     2202        } while ( $depth > 0 );
     2203
    22042204        #
    22052205        # Hash last block text that wasn't processed inside the loop.
    22062206        #
    2207         $parsed .= $this->$hash_method($block_text);
    2208        
    2209         return array($parsed, $text);
    2210     }
    2211 
    2212 
    2213     function hashClean($text) {
    2214     #
    2215     # Called whenever a tag must be hashed when a function insert a "clean" tag
    2216     # in $text, it pass through this function and is automaticaly escaped,
    2217     # blocking invalid nested overlap.
    2218     #
    2219         return $this->hashPart($text, 'C');
    2220     }
    2221 
    2222 
    2223     function doHeaders($text) {
    2224     #
    2225     # Redefined to add id attribute support.
    2226     #
     2207        $parsed .= $this->$hash_method( $block_text );
     2208
     2209        return array( $parsed, $text );
     2210    }
     2211
     2212    function hashClean( $text ) {
     2213        #
     2214        # Called whenever a tag must be hashed when a function insert a "clean" tag
     2215        # in $text, it pass through this function and is automaticaly escaped,
     2216        # blocking invalid nested overlap.
     2217        #
     2218        return $this->hashPart( $text, 'C' );
     2219    }
     2220
     2221    function doHeaders( $text ) {
     2222        #
     2223        # Redefined to add id attribute support.
     2224        #
    22272225        # Setext-style headers:
    22282226        #     Header 1  {#header1}
    22292227        #     ========
    2230         # 
     2228        #
    22312229        #     Header 2  {#header2}
    22322230        #     --------
     
    22382236                [ ]*\n(=+|-+)[ ]*\n+                # $3: Header footer
    22392237            }mx',
    2240             array(&$this, '_doHeaders_callback_setext'), $text);
     2238            array( &$this, '_doHeaders_callback_setext' ), $text );
    22412239
    22422240        # atx-style headers:
     
    22472245        #   ###### Header 6   {#header2}
    22482246        #
    2249         $text = preg_replace_callback('{
     2247        $text = preg_replace_callback( '{
    22502248                ^(\#{1,6})  # $1 = string of #\'s
    22512249                [ ]*
     
    22572255                \n+
    22582256            }xm',
    2259             array(&$this, '_doHeaders_callback_atx'), $text);
     2257            array( &$this, '_doHeaders_callback_atx' ), $text );
    22602258
    22612259        return $text;
    22622260    }
    2263     function _doHeaders_attr($attr) {
    2264         if (empty($attr))  return "";
     2261
     2262    function _doHeaders_attr( $attr ) {
     2263        if ( empty( $attr ) ) {
     2264            return "";
     2265        }
     2266
    22652267        return " id=\"$attr\"";
    22662268    }
    2267     function _doHeaders_callback_setext($matches) {
    2268         if ($matches[3] == '-' && preg_match('{^- }', $matches[1]))
     2269
     2270    function _doHeaders_callback_setext( $matches ) {
     2271        if ( $matches[3] == '-' && preg_match( '{^- }', $matches[1] ) ) {
    22692272            return $matches[0];
     2273        }
    22702274        $level = $matches[3]{0} == '=' ? 1 : 2;
    2271         $attr  = $this->_doHeaders_attr($id =& $matches[2]);
    2272         $block = "<h$level$attr>".$this->runSpanGamut($matches[1])."</h$level>";
    2273         return "\n" . $this->hashBlock($block) . "\n\n";
    2274     }
    2275     function _doHeaders_callback_atx($matches) {
    2276         $level = strlen($matches[1]);
    2277         $attr  = $this->_doHeaders_attr($id =& $matches[3]);
    2278         $block = "<h$level$attr>".$this->runSpanGamut($matches[2])."</h$level>";
    2279         return "\n" . $this->hashBlock($block) . "\n\n";
    2280     }
    2281 
    2282 
    2283     function doTables($text) {
    2284     #
    2285     # Form HTML tables.
    2286     #
     2275        $attr  = $this->_doHeaders_attr( $id =& $matches[2] );
     2276        $block = "<h$level$attr>" . $this->runSpanGamut( $matches[1] ) . "</h$level>";
     2277
     2278        return "\n" . $this->hashBlock( $block ) . "\n\n";
     2279    }
     2280
     2281    function _doHeaders_callback_atx( $matches ) {
     2282        $level = strlen( $matches[1] );
     2283        $attr  = $this->_doHeaders_attr( $id =& $matches[3] );
     2284        $block = "<h$level$attr>" . $this->runSpanGamut( $matches[2] ) . "</h$level>";
     2285
     2286        return "\n" . $this->hashBlock( $block ) . "\n\n";
     2287    }
     2288
     2289    function doTables( $text ) {
     2290        #
     2291        # Form HTML tables.
     2292        #
    22872293        $less_than_tab = $this->tab_width - 1;
    22882294        #
     
    22942300        #   | Cell 3   | Cell 4
    22952301        #
    2296         $text = preg_replace_callback('
     2302        $text = preg_replace_callback( '
    22972303            {
    22982304                ^                           # Start of a line
    2299                 [ ]{0,'.$less_than_tab.'}   # Allowed whitespace.
     2305                [ ]{0,' . $less_than_tab . '}   # Allowed whitespace.
    23002306                [|]                         # Optional leading pipe (present)
    23012307                (.+) \n                     # $1: Header row (at least one pipe)
    2302                
    2303                 [ ]{0,'.$less_than_tab.'}   # Allowed whitespace.
     2308
     2309                [ ]{0,' . $less_than_tab . '}   # Allowed whitespace.
    23042310                [|] ([ ]*[-:]+[-| :]*) \n   # $2: Header underline
    2305                
     2311
    23062312                (                           # $3: Cells
    23072313                    (?>
     
    23122318                (?=\n|\Z)                   # Stop at final double newline.
    23132319            }xm',
    2314             array(&$this, '_doTable_leadingPipe_callback'), $text);
    2315        
     2320            array( &$this, '_doTable_leadingPipe_callback' ), $text );
     2321
    23162322        #
    23172323        # Find tables without leading pipe.
     
    23222328        #   Cell 3   | Cell 4
    23232329        #
    2324         $text = preg_replace_callback('
     2330        $text = preg_replace_callback( '
    23252331            {
    23262332                ^                           # Start of a line
    2327                 [ ]{0,'.$less_than_tab.'}   # Allowed whitespace.
     2333                [ ]{0,' . $less_than_tab . '}   # Allowed whitespace.
    23282334                (\S.*[|].*) \n              # $1: Header row (at least one pipe)
    2329                
    2330                 [ ]{0,'.$less_than_tab.'}   # Allowed whitespace.
     2335
     2336                [ ]{0,' . $less_than_tab . '}   # Allowed whitespace.
    23312337                ([-:]+[ ]*[|][-| :]*) \n    # $2: Header underline
    2332                
     2338
    23332339                (                           # $3: Cells
    23342340                    (?>
     
    23382344                (?=\n|\Z)                   # Stop at final double newline.
    23392345            }xm',
    2340             array(&$this, '_DoTable_callback'), $text);
     2346            array( &$this, '_DoTable_callback' ), $text );
    23412347
    23422348        return $text;
    23432349    }
    2344     function _doTable_leadingPipe_callback($matches) {
    2345         $head       = $matches[1];
    2346         $underline  = $matches[2];
    2347         $content    = $matches[3];
    2348        
     2350
     2351    function _doTable_leadingPipe_callback( $matches ) {
     2352        $head      = $matches[1];
     2353        $underline = $matches[2];
     2354        $content   = $matches[3];
     2355
    23492356        # Remove leading pipe for each row.
    2350         $content    = preg_replace('/^ *[|]/m', '', $content);
    2351        
    2352         return $this->_doTable_callback(array($matches[0], $head, $underline, $content));
    2353     }
    2354     function _doTable_callback($matches) {
    2355         $head       = $matches[1];
    2356         $underline  = $matches[2];
    2357         $content    = $matches[3];
     2357        $content = preg_replace( '/^ *[|]/m', '', $content );
     2358
     2359        return $this->_doTable_callback( array( $matches[0], $head, $underline, $content ) );
     2360    }
     2361
     2362    function _doTable_callback( $matches ) {
     2363        $head      = $matches[1];
     2364        $underline = $matches[2];
     2365        $content   = $matches[3];
    23582366
    23592367        # Remove any tailing pipes for each line.
    2360         $head       = preg_replace('/[|] *$/m', '', $head);
    2361         $underline  = preg_replace('/[|] *$/m', '', $underline);
    2362         $content    = preg_replace('/[|] *$/m', '', $content);
    2363        
     2368        $head      = preg_replace( '/[|] *$/m', '', $head );
     2369        $underline = preg_replace( '/[|] *$/m', '', $underline );
     2370        $content   = preg_replace( '/[|] *$/m', '', $content );
     2371
    23642372        # Reading alignement from header underline.
    2365         $separators = preg_split('/ *[|] */', $underline);
    2366         foreach ($separators as $n => $s) {
    2367             if (preg_match('/^ *-+: *$/', $s))      $attr[$n] = ' align="right"';
    2368             else if (preg_match('/^ *:-+: *$/', $s))$attr[$n] = ' align="center"';
    2369             else if (preg_match('/^ *:-+ *$/', $s)) $attr[$n] = ' align="left"';
    2370             else                                    $attr[$n] = '';
    2371         }
    2372        
    2373         # Parsing span elements, including code spans, character escapes,
     2373        $separators = preg_split( '/ *[|] */', $underline );
     2374        foreach ( $separators as $n => $s ) {
     2375            if ( preg_match( '/^ *-+: *$/', $s ) ) {
     2376                $attr[ $n ] = ' align="right"';
     2377            } else if ( preg_match( '/^ *:-+: *$/', $s ) ) {
     2378                $attr[ $n ] = ' align="center"';
     2379            } else if ( preg_match( '/^ *:-+ *$/', $s ) ) {
     2380                $attr[ $n ] = ' align="left"';
     2381            } else {
     2382                $attr[ $n ] = '';
     2383            }
     2384        }
     2385
     2386        # Parsing span elements, including code spans, character escapes,
    23742387        # and inline HTML tags, so that pipes inside those gets ignored.
    2375         $head       = $this->parseSpan($head);
    2376         $headers    = preg_split('/ *[|] */', $head);
    2377         $col_count  = count($headers);
    2378        
     2388        $head      = $this->parseSpan( $head );
     2389        $headers   = preg_split( '/ *[|] */', $head );
     2390        $col_count = count( $headers );
     2391
    23792392        # Write column headers.
    23802393        $text = "<table>\n";
    23812394        $text .= "<thead>\n";
    23822395        $text .= "<tr>\n";
    2383         foreach ($headers as $n => $header)
    2384             $text .= "  <th$attr[$n]>".$this->runSpanGamut(trim($header))."</th>\n";
     2396        foreach ( $headers as $n => $header ) {
     2397            $text .= "  <th$attr[$n]>" . $this->runSpanGamut( trim( $header ) ) . "</th>\n";
     2398        }
    23852399        $text .= "</tr>\n";
    23862400        $text .= "</thead>\n";
    2387        
     2401
    23882402        # Split content by row.
    2389         $rows = explode("\n", trim($content, "\n"));
    2390        
     2403        $rows = explode( "\n", trim( $content, "\n" ) );
     2404
    23912405        $text .= "<tbody>\n";
    2392         foreach ($rows as $row) {
    2393             # Parsing span elements, including code spans, character escapes, 
     2406        foreach ( $rows as $row ) {
     2407            # Parsing span elements, including code spans, character escapes,
    23942408            # and inline HTML tags, so that pipes inside those gets ignored.
    2395             $row = $this->parseSpan($row);
    2396            
     2409            $row = $this->parseSpan( $row );
     2410
    23972411            # Split row by cell.
    2398             $row_cells = preg_split('/ *[|] */', $row, $col_count);
    2399             $row_cells = array_pad($row_cells, $col_count, '');
    2400            
     2412            $row_cells = preg_split( '/ *[|] */', $row, $col_count );
     2413            $row_cells = array_pad( $row_cells, $col_count, '' );
     2414
    24012415            $text .= "<tr>\n";
    2402             foreach ($row_cells as $n => $cell)
    2403                 $text .= "  <td$attr[$n]>".$this->runSpanGamut(trim($cell))."</td>\n";
     2416            foreach ( $row_cells as $n => $cell ) {
     2417                $text .= "  <td$attr[$n]>" . $this->runSpanGamut( trim( $cell ) ) . "</td>\n";
     2418            }
    24042419            $text .= "</tr>\n";
    24052420        }
    24062421        $text .= "</tbody>\n";
    24072422        $text .= "</table>";
    2408        
    2409         return $this->hashBlock($text) . "\n";
    2410     }
    2411 
    2412    
    2413     function doDefLists($text) {
    2414     #
    2415     # Form HTML definition lists.
    2416     #
     2423
     2424        return $this->hashBlock( $text ) . "\n";
     2425    }
     2426
     2427    function doDefLists( $text ) {
     2428        #
     2429        # Form HTML definition lists.
     2430        #
    24172431        $less_than_tab = $this->tab_width - 1;
    24182432
     
    24212435            (                               # $1 = whole list
    24222436              (                             # $2
    2423                 [ ]{0,'.$less_than_tab.'}
     2437                [ ]{0,' . $less_than_tab . '}
    24242438                ((?>.*\S.*\n)+)             # $3 = defined term
    24252439                \n?
    2426                 [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
     2440                [ ]{0,' . $less_than_tab . '}:[ ]+ # colon starting definition
    24272441              )
    24282442              (?s:.+?)
     
    24332447                  (?=\S)
    24342448                  (?!                       # Negative lookahead for another term
    2435                     [ ]{0,'.$less_than_tab.'}
     2449                    [ ]{0,' . $less_than_tab . '}
    24362450                    (?: \S.*\n )+?          # defined term
    24372451                    \n?
    2438                     [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
     2452                    [ ]{0,' . $less_than_tab . '}:[ ]+ # colon starting definition
    24392453                  )
    24402454                  (?!                       # Negative lookahead for another definition
    2441                     [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
     2455                    [ ]{0,' . $less_than_tab . '}:[ ]+ # colon starting definition
    24422456                  )
    24432457              )
     
    24452459        )'; // mx
    24462460
    2447         $text = preg_replace_callback('{
     2461        $text = preg_replace_callback( '{
    24482462                (?>\A\n?|(?<=\n\n))
    2449                 '.$whole_list_re.'
     2463                ' . $whole_list_re . '
    24502464            }mx',
    2451             array(&$this, '_doDefLists_callback'), $text);
     2465            array( &$this, '_doDefLists_callback' ), $text );
    24522466
    24532467        return $text;
    24542468    }
    2455     function _doDefLists_callback($matches) {
     2469
     2470    function _doDefLists_callback( $matches ) {
    24562471        # Re-usable patterns to match list item bullets and number markers:
    24572472        $list = $matches[1];
    2458        
     2473
    24592474        # Turn double returns into triple returns, so that we can make a
    24602475        # paragraph for the last item in a list, if necessary:
    2461         $result = trim($this->processDefListItems($list));
     2476        $result = trim( $this->processDefListItems( $list ) );
    24622477        $result = "<dl>\n" . $result . "\n</dl>";
    2463         return $this->hashBlock($result) . "\n\n";
    2464     }
    2465 
    2466 
    2467     function processDefListItems($list_str) {
    2468     #
    2469     #   Process the contents of a single definition list, splitting it
    2470     #   into individual term and definition list items.
    2471     #
     2478
     2479        return $this->hashBlock( $result ) . "\n\n";
     2480    }
     2481
     2482    function processDefListItems( $list_str ) {
     2483        #
     2484        #   Process the contents of a single definition list, splitting it
     2485        #   into individual term and definition list items.
     2486        #
    24722487        $less_than_tab = $this->tab_width - 1;
    2473        
     2488
    24742489        # trim trailing blank lines:
    2475         $list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
     2490        $list_str = preg_replace( "/\n{2,}\\z/", "\n", $list_str );
    24762491
    24772492        # Process definition terms.
    2478         $list_str = preg_replace_callback('{
     2493        $list_str = preg_replace_callback( '{
    24792494            (?>\A\n?|\n\n+)                 # leading line
    24802495            (                               # definition terms = $1
    2481                 [ ]{0,'.$less_than_tab.'}   # leading whitespace
    2482                 (?![:][ ]|[ ])              # negative lookahead for a definition 
     2496                [ ]{0,' . $less_than_tab . '}   # leading whitespace
     2497                (?![:][ ]|[ ])              # negative lookahead for a definition
    24832498                                            #   mark (colon) or more whitespace.
    2484                 (?> \S.* \n)+?              # actual term (not whitespace). 
    2485             )           
    2486             (?=\n?[ ]{0,3}:[ ])             # lookahead for following line feed 
     2499                (?> \S.* \n)+?              # actual term (not whitespace).
     2500            )
     2501            (?=\n?[ ]{0,3}:[ ])             # lookahead for following line feed
    24872502                                            #   with a definition mark.
    24882503            }xm',
    2489             array(&$this, '_processDefListItems_callback_dt'), $list_str);
     2504            array( &$this, '_processDefListItems_callback_dt' ), $list_str );
    24902505
    24912506        # Process actual definitions.
    2492         $list_str = preg_replace_callback('{
     2507        $list_str = preg_replace_callback( '{
    24932508            \n(\n+)?                        # leading line = $1
    24942509            (                               # marker space = $2
    2495                 [ ]{0,'.$less_than_tab.'}   # whitespace before colon
     2510                [ ]{0,' . $less_than_tab . '}   # whitespace before colon
    24962511                [:][ ]+                     # definition mark (colon)
    24972512            )
     
    24992514            (?= \n+                         # stop at next definition mark,
    25002515                (?:                         # next term or end of text
    2501                     [ ]{0,'.$less_than_tab.'} [:][ ]    |
     2516                    [ ]{0,' . $less_than_tab . '} [:][ ]    |
    25022517                    <dt> | \z
    2503                 )                       
    2504             )                   
     2518                )
     2519            )
    25052520            }xm',
    2506             array(&$this, '_processDefListItems_callback_dd'), $list_str);
     2521            array( &$this, '_processDefListItems_callback_dd' ), $list_str );
    25072522
    25082523        return $list_str;
    25092524    }
    2510     function _processDefListItems_callback_dt($matches) {
    2511         $terms = explode("\n", trim($matches[1]));
    2512         $text = '';
    2513         foreach ($terms as $term) {
    2514             $term = $this->runSpanGamut(trim($term));
     2525
     2526    function _processDefListItems_callback_dt( $matches ) {
     2527        $terms = explode( "\n", trim( $matches[1] ) );
     2528        $text  = '';
     2529        foreach ( $terms as $term ) {
     2530            $term = $this->runSpanGamut( trim( $term ) );
    25152531            $text .= "\n<dt>" . $term . "</dt>";
    25162532        }
     2533
    25172534        return $text . "\n";
    25182535    }
    2519     function _processDefListItems_callback_dd($matches) {
    2520         $leading_line   = $matches[1];
    2521         $marker_space   = $matches[2];
    2522         $def            = $matches[3];
    2523 
    2524         if ($leading_line || preg_match('/\n{2,}/', $def)) {
     2536
     2537    function _processDefListItems_callback_dd( $matches ) {
     2538        $leading_line = $matches[1];
     2539        $marker_space = $matches[2];
     2540        $def          = $matches[3];
     2541
     2542        if ( $leading_line || preg_match( '/\n{2,}/', $def ) ) {
    25252543            # Replace marker with the appropriate whitespace indentation
    2526             $def = str_repeat(' ', strlen($marker_space)) . $def;
    2527             $def = $this->runBlockGamut($this->outdent($def . "\n\n"));
    2528             $def = "\n". $def ."\n";
    2529         }
    2530         else {
    2531             $def = rtrim($def);
    2532             $def = $this->runSpanGamut($this->outdent($def));
     2544            $def = str_repeat( ' ', strlen( $marker_space ) ) . $def;
     2545            $def = $this->runBlockGamut( $this->outdent( $def . "\n\n" ) );
     2546            $def = "\n" . $def . "\n";
     2547        } else {
     2548            $def = rtrim( $def );
     2549            $def = $this->runSpanGamut( $this->outdent( $def ) );
    25332550        }
    25342551
     
    25362553    }
    25372554
    2538 
    2539     function doFencedCodeBlocks($text) {
    2540     #
    2541     # Adding the fenced code block syntax to regular Markdown:
    2542     #
    2543     # ~~~
    2544     # Code block
    2545     # ~~~
    2546     #
     2555    function doFencedCodeBlocks( $text ) {
     2556        #
     2557        # Adding the fenced code block syntax to regular Markdown:
     2558        #
     2559        # ~~~
     2560        # Code block
     2561        # ~~~
     2562        #
    25472563        $less_than_tab = $this->tab_width;
    2548        
    2549         $text = preg_replace_callback('{
     2564
     2565        $text = preg_replace_callback( '{
    25502566                (?:\n|\A)
    25512567                # 1: Opening marker
     
    25542570                )
    25552571                [ ]* \n # Whitespace and newline following marker.
    2556                
     2572
    25572573                # 2: Content
    25582574                (
     
    25622578                    )+
    25632579                )
    2564                
     2580
    25652581                # Closing marker.
    25662582                \1 [ ]* \n
    25672583            }xm',
    2568             array(&$this, '_doFencedCodeBlocks_callback'), $text);
     2584            array( &$this, '_doFencedCodeBlocks_callback' ), $text );
    25692585
    25702586        return $text;
    25712587    }
    2572     function _doFencedCodeBlocks_callback($matches) {
     2588
     2589    function _doFencedCodeBlocks_callback( $matches ) {
    25732590        $codeblock = $matches[2];
    2574         $codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
    2575         $codeblock = preg_replace_callback('/^\n+/',
    2576             array(&$this, '_doFencedCodeBlocks_newlines'), $codeblock);
     2591        $codeblock = htmlspecialchars( $codeblock, ENT_NOQUOTES );
     2592        $codeblock = preg_replace_callback( '/^\n+/',
     2593            array( &$this, '_doFencedCodeBlocks_newlines' ), $codeblock );
    25772594        $codeblock = "<pre><code>$codeblock</code></pre>";
    2578         return "\n\n".$this->hashBlock($codeblock)."\n\n";
    2579     }
    2580     function _doFencedCodeBlocks_newlines($matches) {
    2581         return str_repeat("<br$this->empty_element_suffix",
    2582             strlen($matches[0]));
     2595
     2596        return "\n\n" . $this->hashBlock( $codeblock ) . "\n\n";
     2597    }
     2598
     2599    function _doFencedCodeBlocks_newlines( $matches ) {
     2600        return str_repeat( "<br$this->empty_element_suffix",
     2601            strlen( $matches[0] ) );
    25832602    }
    25842603
     
    25922611        '*' => '(?<=\S|^)(?<!\*)\*(?!\*)',
    25932612        '_' => '(?<=\S|^)(?<!_)_(?![a-zA-Z0-9_])',
    2594         );
     2613    );
    25952614    var $strong_relist = array(
    25962615        ''   => '(?:(?<!\*)\*\*(?!\*)|(?<![a-zA-Z0-9_])__(?!_))(?=\S|$)(?![.,:;]\s)',
    25972616        '**' => '(?<=\S|^)(?<!\*)\*\*(?!\*)',
    25982617        '__' => '(?<=\S|^)(?<!_)__(?![a-zA-Z0-9_])',
    2599         );
     2618    );
    26002619    var $em_strong_relist = array(
    26012620        ''    => '(?:(?<!\*)\*\*\*(?!\*)|(?<![a-zA-Z0-9_])___(?!_))(?=\S|$)(?![.,:;]\s)',
    26022621        '***' => '(?<=\S|^)(?<!\*)\*\*\*(?!\*)',
    26032622        '___' => '(?<=\S|^)(?<!_)___(?![a-zA-Z0-9_])',
    2604         );
    2605 
    2606 
    2607     function formParagraphs($text) {
    2608     #
    2609     #   Params:
    2610     #       $text - string to process with html <p> tags
    2611     #
     2623    );
     2624
     2625    function formParagraphs( $text ) {
     2626        #
     2627        #   Params:
     2628        #       $text - string to process with html <p> tags
     2629        #
    26122630        # Strip leading and trailing lines:
    2613         $text = preg_replace('/\A\n+|\n+\z/', '', $text);
    2614        
    2615         $grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY);
     2631        $text = preg_replace( '/\A\n+|\n+\z/', '', $text );
     2632
     2633        $grafs = preg_split( '/\n{2,}/', $text, - 1, PREG_SPLIT_NO_EMPTY );
    26162634
    26172635        #
    26182636        # Wrap <p> tags and unhashify HTML blocks
    26192637        #
    2620         foreach ($grafs as $key => $value) {
    2621             $value = trim($this->runSpanGamut($value));
    2622            
     2638        foreach ( $grafs as $key => $value ) {
     2639            $value = trim( $this->runSpanGamut( $value ) );
     2640
    26232641            # Check if this should be enclosed in a paragraph.
    26242642            # Clean tag hashes & block tag hashes are left alone.
    2625             $is_p = !preg_match('/^B\x1A[0-9]+B|^C\x1A[0-9]+C$/', $value);
    2626            
    2627             if ($is_p) {
     2643            $is_p = ! preg_match( '/^B\x1A[0-9]+B|^C\x1A[0-9]+C$/', $value );
     2644
     2645            if ( $is_p ) {
    26282646                $value = "<p>$value</p>";
    26292647            }
    2630             $grafs[$key] = $value;
    2631         }
    2632        
    2633         # Join grafs in one text, then unhash HTML tags. 
    2634         $text = implode("\n\n", $grafs);
    2635        
     2648            $grafs[ $key ] = $value;
     2649        }
     2650
     2651        # Join grafs in one text, then unhash HTML tags.
     2652        $text = implode( "\n\n", $grafs );
     2653
    26362654        # Finish by removing any tag hashes still present in $text.
    2637         $text = $this->unhash($text);
    2638        
     2655        $text = $this->unhash( $text );
     2656
    26392657        return $text;
    26402658    }
    2641    
    2642    
     2659
    26432660    ### Footnotes
    2644    
    2645     function stripFootnotes($text) {
    2646     #
    2647     # Strips link definitions from text, stores the URLs and titles in
    2648     # hash references.
    2649     #
     2661
     2662    function stripFootnotes( $text ) {
     2663        #
     2664        # Strips link definitions from text, stores the URLs and titles in
     2665        # hash references.
     2666        #
    26502667        $less_than_tab = $this->tab_width - 1;
    26512668
    26522669        # Link defs are in the form: [^id]: url "optional title"
    2653         $text = preg_replace_callback('{
    2654             ^[ ]{0,'.$less_than_tab.'}\[\^(.+?)\][ ]?:  # note_id = $1
     2670        $text = preg_replace_callback( '{
     2671            ^[ ]{0,' . $less_than_tab . '}\[\^(.+?)\][ ]?:  # note_id = $1
    26552672              [ ]*
    26562673              \n?                   # maybe *one* newline
    26572674            (                       # text = $2 (no blank lines allowed)
    2658                 (?:                 
     2675                (?:
    26592676                    .+              # actual text
    26602677                |
    2661                     \n              # newlines but 
     2678                    \n              # newlines but
    26622679                    (?!\[\^.+?\]:\s)# negative lookahead for footnote marker.
    2663                     (?!\n+[ ]{0,3}\S)# ensure line is not blank and followed 
     2680                    (?!\n+[ ]{0,3}\S)# ensure line is not blank and followed
    26642681                                    # by non-indented content
    26652682                )*
    2666             )       
     2683            )
    26672684            }xm',
    2668             array(&$this, '_stripFootnotes_callback'),
    2669             $text);
     2685            array( &$this, '_stripFootnotes_callback' ),
     2686            $text );
     2687
    26702688        return $text;
    26712689    }
    2672     function _stripFootnotes_callback($matches) {
    2673         $note_id = $this->fn_id_prefix . $matches[1];
    2674         $this->footnotes[$note_id] = $this->outdent($matches[2]);
     2690
     2691    function _stripFootnotes_callback( $matches ) {
     2692        $note_id                     = $this->fn_id_prefix . $matches[1];
     2693        $this->footnotes[ $note_id ] = $this->outdent( $matches[2] );
     2694
    26752695        return ''; # String that will replace the block
    26762696    }
    26772697
    2678 
    2679     function doFootnotes($text) {
    2680     #
    2681     # Replace footnote references in $text [^id] with a special text-token
    2682     # which will be replaced by the actual footnote marker in appendFootnotes.
    2683     #
    2684         if (!$this->in_anchor) {
    2685             $text = preg_replace('{\[\^(.+?)\]}', "F\x1Afn:\\1\x1A:", $text);
    2686         }
     2698    function doFootnotes( $text ) {
     2699        #
     2700        # Replace footnote references in $text [^id] with a special text-token
     2701        # which will be replaced by the actual footnote marker in appendFootnotes.
     2702        #
     2703        if ( ! $this->in_anchor ) {
     2704            $text = preg_replace( '{\[\^(.+?)\]}', "F\x1Afn:\\1\x1A:", $text );
     2705        }
     2706
    26872707        return $text;
    26882708    }
    26892709
    2690    
    2691     function appendFootnotes($text) {
    2692     #
    2693     # Append footnote list to text.
    2694     #
    2695         $text = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}',
    2696             array(&$this, '_appendFootnotes_callback'), $text);
    2697    
    2698         if (!empty($this->footnotes_ordered)) {
     2710    function appendFootnotes( $text ) {
     2711        #
     2712        # Append footnote list to text.
     2713        #
     2714        $text = preg_replace_callback( '{F\x1Afn:(.*?)\x1A:}',
     2715            array( &$this, '_appendFootnotes_callback' ), $text );
     2716
     2717        if ( ! empty( $this->footnotes_ordered ) ) {
    26992718            $text .= "\n\n";
    27002719            $text .= "<div class=\"footnotes\">\n";
    2701             $text .= "<hr". $this->empty_element_suffix ."\n";
     2720            $text .= "<hr" . $this->empty_element_suffix . "\n";
    27022721            $text .= "<ol>\n\n";
    2703            
     2722
    27042723            $attr = " rev=\"footnote\"";
    2705             if ($this->fn_backlink_class != "") {
     2724            if ( $this->fn_backlink_class != "" ) {
    27062725                $class = $this->fn_backlink_class;
    2707                 $class = $this->encodeAttribute($class);
     2726                $class = $this->encodeAttribute( $class );
    27082727                $attr .= " class=\"$class\"";
    27092728            }
    2710             if ($this->fn_backlink_title != "") {
     2729            if ( $this->fn_backlink_title != "" ) {
    27112730                $title = $this->fn_backlink_title;
    2712                 $title = $this->encodeAttribute($title);
     2731                $title = $this->encodeAttribute( $title );
    27132732                $attr .= " title=\"$title\"";
    27142733            }
    27152734            $num = 0;
    2716            
    2717             while (!empty($this->footnotes_ordered)) {
    2718                 $footnote = reset($this->footnotes_ordered);
    2719                 $note_id = key($this->footnotes_ordered);
    2720                 unset($this->footnotes_ordered[$note_id]);
    2721                
     2735
     2736            while ( ! empty( $this->footnotes_ordered ) ) {
     2737                $footnote = reset( $this->footnotes_ordered );
     2738                $note_id  = key( $this->footnotes_ordered );
     2739                unset( $this->footnotes_ordered[ $note_id ] );
     2740
    27222741                $footnote .= "\n"; # Need to append newline before parsing.
    2723                 $footnote = $this->runBlockGamut("$footnote\n");               
    2724                 $footnote = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}',
    2725                     array(&$this, '_appendFootnotes_callback'), $footnote);
    2726                
    2727                 $attr = str_replace("%%", ++$num, $attr);
    2728                 $note_id = $this->encodeAttribute($note_id);
    2729                
     2742                $footnote = $this->runBlockGamut( "$footnote\n" );
     2743                $footnote = preg_replace_callback( '{F\x1Afn:(.*?)\x1A:}',
     2744                    array( &$this, '_appendFootnotes_callback' ), $footnote );
     2745
     2746                $attr    = str_replace( "%%", ++ $num, $attr );
     2747                $note_id = $this->encodeAttribute( $note_id );
     2748
    27302749                # Add backlink to last paragraph; create new paragraph if needed.
    27312750                $backlink = "<a href=\"#fnref:$note_id\"$attr>&#8617;</a>";
    2732                 if (preg_match('{</p>$}', $footnote)) {
    2733                     $footnote = substr($footnote, 0, -4) . "&#160;$backlink</p>";
     2751                if ( preg_match( '{</p>$}', $footnote ) ) {
     2752                    $footnote = substr( $footnote, 0, - 4 ) . "&#160;$backlink</p>";
    27342753                } else {
    27352754                    $footnote .= "\n\n<p>$backlink</p>";
    27362755                }
    2737                
     2756
    27382757                $text .= "<li id=\"fn:$note_id\">\n";
    27392758                $text .= $footnote . "\n";
    27402759                $text .= "</li>\n\n";
    27412760            }
    2742            
     2761
    27432762            $text .= "</ol>\n";
    27442763            $text .= "</div>";
    27452764        }
     2765
    27462766        return $text;
    27472767    }
    2748     function _appendFootnotes_callback($matches) {
     2768
     2769    function _appendFootnotes_callback( $matches ) {
    27492770        $node_id = $this->fn_id_prefix . $matches[1];
    2750        
     2771
    27512772        # Create footnote marker only if it has a corresponding footnote *and*
    27522773        # the footnote hasn't been used by another marker.
    2753         if (isset($this->footnotes[$node_id])) {
     2774        if ( isset( $this->footnotes[ $node_id ] ) ) {
    27542775            # Transfert footnote content to the ordered list.
    2755             $this->footnotes_ordered[$node_id] = $this->footnotes[$node_id];
    2756             unset($this->footnotes[$node_id]);
    2757            
    2758             $num = $this->footnote_counter++;
     2776            $this->footnotes_ordered[ $node_id ] = $this->footnotes[ $node_id ];
     2777            unset( $this->footnotes[ $node_id ] );
     2778
     2779            $num  = $this->footnote_counter ++;
    27592780            $attr = " rel=\"footnote\"";
    2760             if ($this->fn_link_class != "") {
     2781            if ( $this->fn_link_class != "" ) {
    27612782                $class = $this->fn_link_class;
    2762                 $class = $this->encodeAttribute($class);
     2783                $class = $this->encodeAttribute( $class );
    27632784                $attr .= " class=\"$class\"";
    27642785            }
    2765             if ($this->fn_link_title != "") {
     2786            if ( $this->fn_link_title != "" ) {
    27662787                $title = $this->fn_link_title;
    2767                 $title = $this->encodeAttribute($title);
     2788                $title = $this->encodeAttribute( $title );
    27682789                $attr .= " title=\"$title\"";
    27692790            }
    2770            
    2771             $attr = str_replace("%%", $num, $attr);
    2772             $node_id = $this->encodeAttribute($node_id);
    2773            
     2791
     2792            $attr    = str_replace( "%%", $num, $attr );
     2793            $node_id = $this->encodeAttribute( $node_id );
     2794
    27742795            return
    2775                 "<sup id=\"fnref:$node_id\">".
    2776                 "<a href=\"#fn:$node_id\"$attr>$num</a>".
     2796                "<sup id=\"fnref:$node_id\">" .
     2797                "<a href=\"#fn:$node_id\"$attr>$num</a>" .
    27772798                "</sup>";
    27782799        }
    2779        
    2780         return "[^".$matches[1]."]";
    2781     }
    2782        
    2783    
     2800
     2801        return "[^" . $matches[1] . "]";
     2802    }
     2803
    27842804    ### Abbreviations ###
    2785    
    2786     function stripAbbreviations($text) {
    2787     #
    2788     # Strips abbreviations from text, stores titles in hash references.
    2789     #
     2805
     2806    function stripAbbreviations( $text ) {
     2807        #
     2808        # Strips abbreviations from text, stores titles in hash references.
     2809        #
    27902810        $less_than_tab = $this->tab_width - 1;
    27912811
    27922812        # Link defs are in the form: [id]*: url "optional title"
    2793         $text = preg_replace_callback('{
    2794             ^[ ]{0,'.$less_than_tab.'}\*\[(.+?)\][ ]?:  # abbr_id = $1
    2795             (.*)                    # text = $2 (no blank lines allowed)   
     2813        $text = preg_replace_callback( '{
     2814            ^[ ]{0,' . $less_than_tab . '}\*\[(.+?)\][ ]?:  # abbr_id = $1
     2815            (.*)                    # text = $2 (no blank lines allowed)
    27962816            }xm',
    2797             array(&$this, '_stripAbbreviations_callback'),
    2798             $text);
     2817            array( &$this, '_stripAbbreviations_callback' ),
     2818            $text );
     2819
    27992820        return $text;
    28002821    }
    2801     function _stripAbbreviations_callback($matches) {
     2822
     2823    function _stripAbbreviations_callback( $matches ) {
    28022824        $abbr_word = $matches[1];
    28032825        $abbr_desc = $matches[2];
    2804         if ($this->abbr_word_re)
     2826        if ( $this->abbr_word_re ) {
    28052827            $this->abbr_word_re .= '|';
    2806         $this->abbr_word_re .= preg_quote($abbr_word);
    2807         $this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
     2828        }
     2829        $this->abbr_word_re .= preg_quote( $abbr_word );
     2830        $this->abbr_desciptions[ $abbr_word ] = trim( $abbr_desc );
     2831
    28082832        return ''; # String that will replace the block
    28092833    }
    2810    
    2811    
    2812     function doAbbreviations($text) {
    2813     #
    2814     # Find defined abbreviations in text and wrap them in <abbr> elements.
    2815     #
    2816         if ($this->abbr_word_re) {
    2817             // cannot use the /x modifier because abbr_word_re may
     2834
     2835    function doAbbreviations( $text ) {
     2836        #
     2837        # Find defined abbreviations in text and wrap them in <abbr> elements.
     2838        #
     2839        if ( $this->abbr_word_re ) {
     2840            // cannot use the /x modifier because abbr_word_re may
    28182841            // contain significant spaces:
    2819             $text = preg_replace_callback('{'.
    2820                 '(?<![\w\x1A])'.
    2821                 '(?:'.$this->abbr_word_re.')'.
    2822                 '(?![\w\x1A])'.
    2823                 '}',
    2824                 array(&$this, '_doAbbreviations_callback'), $text);
    2825         }
     2842            $text = preg_replace_callback( '{' .
     2843                                           '(?<![\w\x1A])' .
     2844                                           '(?:' . $this->abbr_word_re . ')' .
     2845                                           '(?![\w\x1A])' .
     2846                                           '}',
     2847                array( &$this, '_doAbbreviations_callback' ), $text );
     2848        }
     2849
    28262850        return $text;
    28272851    }
    2828     function _doAbbreviations_callback($matches) {
     2852
     2853    function _doAbbreviations_callback( $matches ) {
    28292854        $abbr = $matches[0];
    2830         if (isset($this->abbr_desciptions[$abbr])) {
    2831             $desc = $this->abbr_desciptions[$abbr];
    2832             if (empty($desc)) {
    2833                 return $this->hashPart("<abbr>$abbr</abbr>");
     2855        if ( isset( $this->abbr_desciptions[ $abbr ] ) ) {
     2856            $desc = $this->abbr_desciptions[ $abbr ];
     2857            if ( empty( $desc ) ) {
     2858                return $this->hashPart( "<abbr>$abbr</abbr>" );
    28342859            } else {
    2835                 $desc = $this->encodeAttribute($desc);
    2836                 return $this->hashPart("<abbr title=\"$desc\">$abbr</abbr>");
     2860                $desc = $this->encodeAttribute( $desc );
     2861
     2862                return $this->hashPart( "<abbr title=\"$desc\">$abbr</abbr>" );
    28372863            }
    28382864        } else {
     
    28402866        }
    28412867    }
    2842 
    28432868}
    2844 
    28452869
    28462870/*
     
    28522876-----------
    28532877
    2854 This is a PHP port of the original Markdown formatter written in Perl 
    2855 by John Gruber. This special "Extra" version of PHP Markdown features 
    2856 further enhancements to the syntax for making additional constructs 
     2878This is a PHP port of the original Markdown formatter written in Perl
     2879by John Gruber. This special "Extra" version of PHP Markdown features
     2880further enhancements to the syntax for making additional constructs
    28572881such as tables and definition list.
    28582882
     
    28842908
    28852909Version History
    2886 --------------- 
     2910---------------
    28872911
    28882912See the readme file for detailed release notes for this version.
     
    28922916---------------------
    28932917
    2894 PHP Markdown & Extra 
    2895 Copyright (c) 2004-2009 Michel Fortin 
    2896 <http://michelf.com/> 
     2918PHP Markdown & Extra
     2919Copyright (c) 2004-2009 Michel Fortin
     2920<http://michelf.com/>
    28972921All rights reserved.
    28982922
    2899 Based on Markdown 
    2900 Copyright (c) 2003-2006 John Gruber   
    2901 <http://daringfireball.net/>   
     2923Based on Markdown
     2924Copyright (c) 2003-2006 John Gruber
     2925<http://daringfireball.net/>
    29022926All rights reserved.
    29032927
Note: See TracChangeset for help on using the changeset viewer.