* Copyright (c) 2005, Cake Software Foundation, Inc. * 1785 E. Sahara Avenue, Suite 490-204 * Las Vegas, Nevada 89104 * * Licensed under The MIT License * Redistributions of files must retain the above copyright notice. * * @filesource * @copyright Copyright (c) 2005, Cake Software Foundation, Inc. * @link http://www.cakefoundation.org/projects/info/cakephp CakePHP Project * @package cake * @subpackage cake.cake.libs * @since CakePHP v 0.2.9 * @version $Revision$ * @modifiedby $LastChangedBy$ * @lastmodified $Date$ * @license http://www.opensource.org/licenses/mit-license.php The MIT License */ /** * Included libraries. * */ if(!class_exists('Object')) { uses('object'); } /** * Text-to-HTML parser. * * Text-to-html parser, similar to Textile or RedCloth, only with a little different syntax. * * @package cake * @subpackage cake.cake.libs * @since CakePHP v 0.2.9 */ class Flay extends Object { /** * Text to be parsed. * * @var string */ var $text = null; /** * Set this to allow HTML in the markup. * * @var boolean */ var $allow_html = false; /** * Constructor. * * @param string $text */ function __construct ($text=null) { $this->text = $text; parent::__construct(); } /** * Returns given text translated to HTML using the Flay syntax. * * @param string $text String to format * @param boolean $bare Set this to only do

transforms and > to >, no typography additions. * @param boolean $allowHtml Set this to trim whitespace and disable all HTML * @return string Formatted text */ function toHtml ($text=null, $bare=false, $allowHtml=false) { if (empty($text) && empty($this->text)) { return false; } $text = $text? $text: $this->text; // trim whitespace and disable all HTML if ($allowHtml) { $text = trim($text); } else { $text = str_replace('<', '<', str_replace('>', '>', trim($text))); } if (!$bare) { // multi-paragraph functions $text = preg_replace('#(?:[\n]{0,2})"""(.*)"""(?:[\n]{0,2})#s', "\n\n%BLOCKQUOTE%\n\n\\1\n\n%ENDBLOCKQUOTE%\n\n", $text); $text = preg_replace('#(?:[\n]{0,2})===(.*)===(?:[\n]{0,2})#s', "\n\n%CENTER%\n\n\\1\n\n%ENDCENTER%\n\n", $text); } // pre-parse newlines $text = preg_replace("#\r\n#", "\n", $text); $text = preg_replace("#[\n]{2,}#", "%PARAGRAPH%", $text); $text = preg_replace('#[\n]{1}#', "%LINEBREAK%", $text); // split into paragraphs and parse $out = ''; foreach (split('%PARAGRAPH%', $text) as $line) { if ($line) { if (!$bare) { // pre-parse links $links = array(); $regs = null; if (preg_match_all('#\[([^\[]{4,})\]#', $line, $regs)) { foreach ($regs[1] as $reg) { $links[] = $reg; $line = str_replace("[{$reg}]",'%LINK'.(count($links)-1).'%', $line); } } // MAIN TEXT FUNCTIONS // bold $line = ereg_replace("\*([^\*]*)\*", "\\1", $line); // italic $line = ereg_replace("_([^_]*)_", "\\1", $line); } // entities $line = str_replace(' - ', ' – ', $line); $line = str_replace(' -- ', ' — ', $line); $line = str_replace('(C)', '©', $line); $line = str_replace('(R)', '®', $line); $line = str_replace('(TM)', '™', $line); // guess e-mails $emails = null; if (preg_match_all("#([_A-Za-z0-9+-+]+(?:\.[_A-Za-z0-9+-]+)*@[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)*)#", $line, $emails)) { foreach ($emails[1] as $email) { $line = str_replace($email, "{$email}", $line); } } if (!$bare) { // guess links $urls = null; if (preg_match_all("#((?:http|https|ftp|nntp)://[^ ]+)#", $line, $urls)) { foreach ($urls[1] as $url) { $line = str_replace($url, "{$url}", $line); } } if (preg_match_all("#(www\.[^\n\%\ ]+[^\n\%\,\.\ ])#", $line, $urls)) { foreach ($urls[1] as $url) { $line = str_replace($url, "{$url}", $line); } } // re-parse links if (count($links)) { for ($ii=0; $ii"; } elseif (preg_match('#^([^\]\ ]+)(?:\ ([^\]]+))?$#', $links[$ii], $regs)) { if (isset($regs[2])) { if (preg_match('#\.(jpg|jpeg|gif|png)$#', $regs[2])) { $body = "\"\""; } else { $body = $regs[2]; } } else { $body = $links[$ii]; } $with = "{$body}"; } else { $with = $prefix.$links[$ii]; } $line = str_replace("%LINK{$ii}%", $with, $line); } } } // re-parse newlines $out .= str_replace('%LINEBREAK%', "
\n", "

{$line}

\n"); } } if (!$bare) { // re-parse multilines $out = str_replace('

%BLOCKQUOTE%

', "
", $out); $out = str_replace('

%ENDBLOCKQUOTE%

', "
", $out); $out = str_replace('

%CENTER%

', "
", $out); $out = str_replace('

%ENDCENTER%

', "
", $out); } return $out; } /** * Return the words of the string as an array. * * @param string $string * @return array Array of words */ function extractWords ($string) { return preg_split('/[\s,\.:\/="!\(\)<>~\[\]]+/', $string); } /** * Return given string with words in array colorMarked, up to a number of times (defaults to 5). * * @param array $words Words to look for and markup * @param string $string String to look in * @param integer $max_snippets Max number of snippets to extract * @return string * @see colorMark */ function markedSnippets ($words, $string, $max_snippets=5) { $string = strip_tags($string); $snips = array(); $rest = $string; foreach ($words as $word) { if (preg_match_all("/[\s,]+.{0,40}{$word}.{0,40}[\s,]+/i", $rest, $r)) { foreach ($r as $result) { $rest = str_replace($result, '', $rest); } $snips = array_merge($snips, $r[0]); } } if (count($snips) > $max_snippets) { $snips = array_slice($snips, 0, $max_snippets); } $joined = join(' ... ', $snips); $snips = $joined? "... {$joined} ...": substr($string, 0, 80) . '...'; return Flay::colorMark($words, $snips); } /** * Returns string with EM elements with color classes added. * * @param array $words Array of words to be colorized * @param string $string Text in which the words might be found * @return string */ function colorMark($words, $string) { $colors = array('yl','gr','rd','bl','fu','cy'); $nextColorIndex = 0; foreach ($words as $word) { $string = preg_replace("/({$word})/i", '\\1", $string); $nextColorIndex++; } return $string; } /** * Returns given text with tags stripped out. * * @param string $text * @return string */ function toClean ($text) { return strip_tags(html_entity_decode($text, ENT_QUOTES)); } /** * Return parsed text with tags stripped out. * * @param string $text * @return string */ function toParsedAndClean ($text) { return Flay::toClean(Flay::toHtml($text)); } /** * Return a fragment of a text, up to $length characters long, with an ellipsis after it. * * @param string $text Text to be truncated. * @param integer $length Max length of text. * @param string $ellipsis Sign to print after truncated text. * @return string */ function fragment ($text, $length, $ellipsis='...') { $soft = $length - 5; $hard = $length + 5; $rx = '/(.{' . $soft . ',' . $hard . '})[\s,\.:\/="!\(\)<>~\[\]]+.*/'; if (preg_match($rx, $text, $r)) { $out = $r[1]; } else { $out = substr($text, 0, $length); } $out = $out . (strlen($out)