First version of Markdown converter.
Not complete, but there is a workbase git-svn-id: https://svn.fournier38.fr/svn/ProgSVN/trunk@1282 bf3deb0d-5f1a-0410-827f-c0cc1f45334c
This commit is contained in:
248
markdown.php
Normal file
248
markdown.php
Normal file
@@ -0,0 +1,248 @@
|
||||
<?php
|
||||
/** DomFramework
|
||||
@package domframework
|
||||
@author Dominique Fournier <dominique@fournier38.fr> */
|
||||
|
||||
function debug ($msg)
|
||||
{
|
||||
$trace = debug_backtrace();
|
||||
$back = reset ($trace);
|
||||
file_put_contents ("/tmp/debug", "[".$back["line"]."] $msg\n", FILE_APPEND);
|
||||
}
|
||||
error_reporting (E_ALL);
|
||||
/** Markdown management */
|
||||
class markdown
|
||||
{
|
||||
/** Convert the markdown language to HTML
|
||||
Return the HTML string
|
||||
@param string $mark Message in markdown syntax to display */
|
||||
public function html ($mark)
|
||||
{
|
||||
$res = "";
|
||||
$search = array ();
|
||||
$replace = array ();
|
||||
|
||||
// VALIDATION
|
||||
// if (substr ($mark, -1) !== "\n")
|
||||
// $mark .= "\n";
|
||||
|
||||
// SEPARATORS : *** --- ___ * * * - - - _ _ _
|
||||
// Must be placed before EMPHASIS
|
||||
$search[] = "/\\n^[*_-] ?[*_-] ?[*_-]$/Um";
|
||||
$replace[] = "</p>\n<hr/>\n<p>";
|
||||
|
||||
// EMPHASIS : _ or * for normal, __ or ** for strong
|
||||
$search[] = "/__(.+)__/"; $replace[] = "<strong>\\1</strong>";
|
||||
$search[] = "/_(.+)_/"; $replace[] = "<em>\\1</em>";
|
||||
$search[] = "/\*\*(.+)\*\*/"; $replace[] = "<strong>\\1</strong>";
|
||||
$search[] = "/\*(.+)\*/"; $replace[] = "<em>\\1</em>";
|
||||
|
||||
// CODE : `code` -> <code>
|
||||
$search[] = "/\\n?\`((\\n|.)+)\`/Um";
|
||||
$replace[] = " <code>\\1</code>";
|
||||
|
||||
// LINKS
|
||||
// [Google Site](http://google.fr/ "With help bubble")
|
||||
$search[] = "(\[(.+)\]\((https?://.+) \"(.+)\"\))";
|
||||
$replace[] = "<a href='\\2' title='\\3'>\\1</a>";
|
||||
// [Google Site](http://google.fr/)
|
||||
$search[] = "(\[(.+)\]\((http.+)\))"; $replace[] = "<a href='\\2'>\\1</a>";
|
||||
// Automatics links :
|
||||
// <http://dominique.fournier38.fr>
|
||||
// <dominique@fournier38.fr>
|
||||
$search[] = "(\<(https?://.+)\>)"; $replace[] = "<a href='\\1'>\\1</a>";
|
||||
$search[] = "(\<(.+@.+)\>)"; $replace[] = "<a href='mailto:\\1'>\\1</a>";
|
||||
// TODO : Links by reference :
|
||||
// Voici un petit texte écrit par [Michel Fortin][mf].
|
||||
// [mf]: http://michelf.ca/ "Mon site web"
|
||||
|
||||
// TITLES
|
||||
// Titles ATX (Optionnal sharp at the end)
|
||||
// ###### Title6
|
||||
$search[] = "/\\n^###### ([^#]+)(#*)$\\n/Um";
|
||||
$replace[] = "</p>\n<h6>\\1</h6>\n<p>";
|
||||
// ##### Title5
|
||||
$search[] = "/\\n^##### ([^#]+)(#*)$\\n/Um";
|
||||
$replace[] = "</p>\n<h5>\\1</h5>\n<p>";
|
||||
// #### Title4
|
||||
$search[] = "/\\n^#### ([^#]+)(#*)$\\n/Um";
|
||||
$replace[] = "</p>\n<h4>\\1</h4>\n<p>";
|
||||
// ### Title3
|
||||
$search[] = "/\\n^### ([^#]+)(#*)$\\n/Um";
|
||||
$replace[] = "</p>\n<h3>\\1</h3>\n<p>";
|
||||
// ## Title2
|
||||
$search[] = "/\\n^## ([^#]+)(#*)$\\n/Um";
|
||||
$replace[] = "</p>\n<h2>\\1</h2>\n<p>";
|
||||
// # Title1
|
||||
$search[] = "/\\n^# ([^#]+)(#*)$\\n/Um";
|
||||
$replace[] = "</p>\n<h1>\\1</h1>\n<p>";
|
||||
// Titles with underline (SeText)
|
||||
// Titre1
|
||||
// ======
|
||||
$search[] = "/\\n^(.+)\\n==+$\\n/Um";
|
||||
$replace[] = "</p>\n<h1>\\1</h1>\n<p>";
|
||||
// Titre2
|
||||
// ------
|
||||
$search[] = "/\\n^(.+)\\n--+$\\n/Um";
|
||||
$replace[] = "</p>\n<h2>\\1</h2>\n<p>";
|
||||
|
||||
// End of line with double space : <br/>
|
||||
$search[] = "/( )$/Um"; $replace[] = "<br/>";
|
||||
|
||||
$res = preg_replace ($search, $replace, $mark);
|
||||
|
||||
$res = $this->paragraph ($res);
|
||||
return $res;
|
||||
}
|
||||
|
||||
/** Recursive function to translate the paragraphs
|
||||
return the html */
|
||||
private function paragraph ($mark)
|
||||
{
|
||||
$debug = 1;
|
||||
$mark = str_replace ("\t", " ", $mark);
|
||||
$spacer = " ";
|
||||
$res = "";
|
||||
// P, OL, UL (but not LI !)
|
||||
// Use to found the changing of types
|
||||
$typeStack = array ();
|
||||
// Number of spaces
|
||||
$indentStack = array (-1);
|
||||
// All the HTML stack (with LI)
|
||||
$htmlStack = array ();
|
||||
$lines = explode ("\n", $mark);
|
||||
foreach ($lines as $line)
|
||||
{
|
||||
debug ( "DEBUT:$line");
|
||||
$type = $this->paragraphType ($line);
|
||||
debug ( "DEBUT: Type='$type'");
|
||||
$matches = array ();
|
||||
switch ($type)
|
||||
{
|
||||
case "ol" :
|
||||
preg_match ("/^( *)[0-9]+\. +(.*)/", $line, $matches);
|
||||
$lineTxt = $matches[2];
|
||||
break ;
|
||||
case "ul" :
|
||||
preg_match ("/^( *)[-+*] +(.*)/", $line, $matches);
|
||||
$lineTxt = $matches[2];
|
||||
break ;
|
||||
default:
|
||||
$lineTxt = $line;
|
||||
}
|
||||
$indent = strspn ($line, " ");
|
||||
debug ( "DEBUT: Indent='$indent'");
|
||||
|
||||
// Spacing
|
||||
if ($indent < end ($indentStack))
|
||||
{
|
||||
debug ( "DEB1 : Ending of block");
|
||||
if (end ($htmlStack) === "li")
|
||||
{
|
||||
debug ("Pending <Li> : closing");
|
||||
debug ("</li>");
|
||||
$res .= "</li>";
|
||||
array_pop ($htmlStack);
|
||||
}
|
||||
$oldType = array_pop ($typeStack);
|
||||
debug (str_repeat (" ", end ($indentStack))."</$oldType>");
|
||||
$res .= "\n".str_repeat (" ", end ($indentStack))."</$oldType>";
|
||||
array_pop ($htmlStack);
|
||||
if ($type === "ol" || $type === "ul")
|
||||
{
|
||||
debug ("DEB2 : Pending <Li> : closing");
|
||||
debug ("</li>");
|
||||
$res .= "\n</li>";
|
||||
array_pop ($htmlStack);
|
||||
debug ("DEB2 : Adding li");
|
||||
$htmlStack[] = "li";
|
||||
debug ( str_repeat (" ", $indent)."<li>");
|
||||
$res .= "\n".str_repeat (" ", $indent)."<li>";
|
||||
}
|
||||
debug (str_repeat (" ", $indent)."$lineTxt");
|
||||
$res .= str_repeat (" ", $indent)."$lineTxt";
|
||||
array_pop ($indentStack);
|
||||
}
|
||||
elseif ($indent > end ($indentStack))
|
||||
{
|
||||
debug ( "DEB1 : Starting a new block");
|
||||
array_push ($indentStack, $indent);
|
||||
array_push ($typeStack, $type);
|
||||
debug ( str_repeat (" ", $indent)."<$type>");
|
||||
$res .= "\n".str_repeat (" ", $indent)."<$type>";
|
||||
$htmlStack[] = $type;
|
||||
if ($type === "ol" || $type === "ul")
|
||||
{
|
||||
debug ("DEB2 : Adding li");
|
||||
$htmlStack[] = "li";
|
||||
debug ( str_repeat (" ", $indent)."<li>");
|
||||
$res .= "\n".str_repeat (" ", $indent)."<li>";
|
||||
}
|
||||
debug ( "$lineTxt");
|
||||
$res .= "$lineTxt";
|
||||
}
|
||||
else
|
||||
{
|
||||
debug ( "DEB1 : Continuous block $type/".end ($typeStack));
|
||||
if (end ($htmlStack) === "li")
|
||||
{
|
||||
debug ("Pending <Li> : closing");
|
||||
debug ("</li>");
|
||||
$res .= "</li>";
|
||||
array_pop ($htmlStack);
|
||||
}
|
||||
debug ( "DEB1 : Continuous block $type/".end ($typeStack)." SECOND");
|
||||
if ($type !== end ($typeStack))
|
||||
{
|
||||
debug ( "DEB2 : Continuous Block but type change");
|
||||
$oldType = array_pop ($typeStack);
|
||||
debug (str_repeat (" ", end ($indentStack))."</$oldType>");
|
||||
$res .= "\n".str_repeat (" ", end ($indentStack))."</$oldType>";
|
||||
array_pop ($htmlStack);
|
||||
|
||||
debug (str_repeat (" ", end ($indentStack))."<$type>");
|
||||
$res .= "\n".str_repeat (" ", end ($indentStack))."<$type>";
|
||||
$htmlStack[] = $type;
|
||||
array_push ($indentStack, $indent);
|
||||
array_push ($typeStack, $type);
|
||||
}
|
||||
|
||||
if ($type === "ol" || $type === "ul")
|
||||
{
|
||||
debug ("DEB2 : Adding li");
|
||||
$htmlStack[] = "li";
|
||||
debug ( str_repeat (" ", $indent)."<li>");
|
||||
$res .= "\n".str_repeat (" ", $indent)."<li>";
|
||||
}
|
||||
|
||||
debug ("$lineTxt");
|
||||
$res .= "$lineTxt";
|
||||
}
|
||||
}
|
||||
|
||||
debug ( "DEB1 : End of loop");
|
||||
$htmlStack = array_reverse ($htmlStack);
|
||||
foreach ($htmlStack as $type)
|
||||
{
|
||||
debug ( "FIN</$type>");
|
||||
$res .= "</$type>\n";
|
||||
}
|
||||
|
||||
debug ( "-----------\n");
|
||||
return $res;
|
||||
}
|
||||
|
||||
/** Return the Type of object in the provided line
|
||||
p, ul, ol, code */
|
||||
private function paragraphType ($line)
|
||||
{
|
||||
$line = ltrim ($line);
|
||||
if (! isset ($line{0}))
|
||||
return "";
|
||||
if ($line{0} === "*" || $line{0} === "-" || $line{0} === "+")
|
||||
return "ul";
|
||||
if (preg_match ("/^[0-9]+\. /", $line) === 1)
|
||||
return "ol";
|
||||
return "p";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user