<?php
/*
--------------------------------------------------------------------
TypeFriendly
Copyright (c) 2008-2010 Invenzzia Team
http://www.invenzzia.org/
See README for more author details
--------------------------------------------------------------------
This file is part of TypeFriendly.
TypeFriendly is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
TypeFriendly is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with TypeFriendly. If not, see <http://www.gnu.org/licenses/>.
*/
// $Id: markdown.php 68 2010-01-16 11:11:50Z extremo $
@define('MARKDOWN_PARSER_CLASS', 'MarkdownDocs_Parser');
require_once TF_VENDOR.'markdown/markdown.php';
require_once TF_VENDOR.'geshi/geshi.php';
/*
Original Markdown parser is written in PHP4, so I don't think it is
necessary to use 'private' and 'public' in functions here
- eXtreme
*/
class MarkdownDocs_Parser extends MarkdownExtra_Parser
{
var $page_id = '';
function _doCodeBlocks_callback($matches)
{
$codeblock = $matches[1];
$codeblock = $this->outdent($codeblock);
# trim leading newlines and trailing newlines
$codeblock = preg_replace('/\A\n+|\n+\z/', '', $codeblock);
$clear = true;
$codeblock = $this->_codeBlockHighlighter($codeblock, $clear);
if($clear)
{
$codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
$codeblock = "<pre><code>$codeblock\n</code></pre>";
}
return "\n\n".$this->hashBlock($codeblock)."\n\n";
} // end _doCodeBlocks_callback();
function _doFencedCodeBlocks_callback($matches)
{
$codeblock = $matches[2];
$clear = true;
$codeblock = $this->_codeBlockHighlighter($codeblock, $clear);
if($clear)
{
$codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
$codeblock = preg_replace_callback('/^\n+/', array($this, '_doFencedCodeBlocks_newlines'), $codeblock);
$codeblock = "<pre><code>$codeblock</code></pre>";
}
return "\n\n".$this->hashBlock($codeblock)."\n\n";
} // end _doFencedCodeBlocks_callback();
function _codeBlockHighlighter($codeblock, &$clear)
{
$split = preg_split('/[\r\n]/', $codeblock, 2, PREG_SPLIT_NO_EMPTY);
if(count($split) == 2 && preg_match('/^\s*((\\\){0,2}\[([a-zA-Z0-9\-_]+)\]\s*)/', $split[0], $matches))
{
if($matches[2] == '\\')
{
$codeblock = substr($codeblock, 1);
return $codeblock;
}
$strlen = strlen($matches[0]);
$parser = strtolower($matches[3]);
$codeblock = $split[1];
if($strlen > 0)
{
if($parser == 'console')
{
$codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
$codeblock = preg_replace_callback('/^\n+/', array($this, '_doFencedCodeBlocks_newlines'), $codeblock);
$codeblock = "<pre class=\"console\"><code>$codeblock</code></pre>";
}
else
{
$codeblock = preg_replace('/\n+$/', '', $codeblock);
$geshi = new GeSHi($codeblock, $parser);
$geshi->set_overall_style('');
$codeblock = $geshi->parse_code();
}
$clear = false;
}
}
return $codeblock;
} // end _codeBlockHighlighter();
function _doBlockQuotes_callback($matches)
{
$bq = $matches[1];
# trim one level of quoting - trim whitespace-only lines
$bq = preg_replace('/^[ ]*>[ ]?|^[ ]+$/m', '', $bq);
$addClass = '';
if(preg_match('/^((\\\){0,2}\[([a-zA-Z0-9\-_]+)\]\s*\n)/', $bq, $matches))
{
if($matches[2] == '\\')
{
$bq = substr($bq, 1);
}
else
{
$strlen = strlen($matches[1]);
$parser = strtolower($matches[3]);
if($strlen > 0)
{
$bq = substr($bq, $strlen);
$addClass = ' class="'.$parser.'"';
}
}
}
$bq = $this->runBlockGamut($bq); # recurse
$bq = preg_replace('/^/m', " ", $bq);
# These leading spaces cause problem with <pre> content,
# so we need to fix that:
$bq = preg_replace_callback('{(\s*<pre[^>]*>.+?</pre>)}sx',
array(&$this, '_DoBlockQuotes_callback2'), $bq);
return "\n".$this->hashBlock("<blockquote$addClass>\n$bq\n</blockquote>")."\n\n";
} // end _doBlockQuotes_callback();
function _doHeaders_attr($attr)
{
if(empty($attr)) return "";
return ' id="h:'.str_replace('.', '_', $this->page_id).':'.$attr.'"';
} // end _doHeaders_attr();
function _doHeaders_callback_setext($matches)
{
if($matches[3] == '-' && preg_match('{^- }', $matches[1]))
return $matches[0];
$level = $matches[3]{0} == '=' ? 1 : 2;
$level += 1;
$attr = $this->_doHeaders_attr($id =& $matches[2]);
$block = "<h$level$attr>".$this->runSpanGamut($matches[1])."</h$level>";
return "\n".$this->hashBlock($block)."\n\n";
} // end _doHeaders_callback_setext();
function _doHeaders_callback_atx($matches)
{
$level = strlen($matches[1]);
$level += 1;
if($level > 6)
$level = 6;
$attr = $this->_doHeaders_attr($id =& $matches[3]);
$block = "<h$level$attr>".$this->runSpanGamut($matches[2])."</h$level>";
return "\n".$this->hashBlock($block)."\n\n";
} // end _doHeaders_callback_atx();
function _doAnchors_reference_callback($matches)
{
$whole_match = $matches[1];
$res = parent::_doAnchors_reference_callback($matches);
if($res != $whole_match || strpos($matches[3], '#') === false)
{
return $res;
}
list($matches[3], $anchor) = explode('#', $matches[3], 2);
$link_id = strtolower($matches[3]);
$temp = false;
if(isset($this->urls[$link_id]))
{
$temp = $this->urls[$link_id];
$explode = explode('#', $this->urls[$link_id], 2);
if(count($explode) == 2)
{
$this->urls[$link_id] = $explode[0];
}
$this->urls[$link_id] .= '#h:'.str_replace('.', '_', $link_id).':'.$anchor;
}
$res = parent::_doAnchors_reference_callback($matches);
if($temp !== false)
{
$this->urls[$link_id] = $temp;
}
return $res;
} // end _doAnchors_reference_callback();
} // end MarkdownDocs_Parser;