PHP Paragrapher


/ Published in: PHP
Save to your folder(s)

Transform text (eg. from a WYSIWYG) into nicely formatted HTML paragraphs. (Credits: Ludo Magnocavallo's LightPress).

[this is a solid starting point - but a lot of HTML elements are missing]


Copy this code and paste it in your HTML
  1. function linebreaker(&$s) {
  2. if (!preg_match('@<[^>]+\n@sm', $s))
  3. return str_replace("\n", "<br />\n", $s);
  4. $buffer = '';
  5. $inside = false;
  6. for ($i=0;$i<strlen($s);$i++) {
  7. $c = $s[$i];
  8. switch ($c) {
  9. case '<':
  10. $inside = true;
  11. $buffer .= $c;
  12. break;
  13. case '>':
  14. $inside = false;
  15. $buffer .= $c;
  16. break;
  17. case "\n":
  18. $buffer .= ($inside ? "\n" : "<br />\n");
  19. break;
  20. default:
  21. $buffer .= $c;
  22. }
  23. }
  24. return $buffer;
  25. }
  26.  
  27. function &paragrapher(&$s) {
  28.  
  29. if (substr($s, 0, 4) == "\t<p>")
  30. return($s); // already formatted
  31.  
  32. // clean up bare &
  33. $s = preg_replace('@&(?![a-z0-9#]+;)@', '&amp;', $s);
  34.  
  35. // code should be inside pre to be preformatted, let's leave it here for now anyway
  36. $block_tags = 'object|pre|p|dl|div|noscript|script|blockquote|form|table|td|th|ins|fieldset|address|h1|h2|h3|h4|h5|h6|ul|ol|li|code';
  37.  
  38. $r = '@(?:
  39. # match paragraph mark
  40. ((?:\n\s*){2,})
  41. | # match block open tag
  42. (< # save tag
  43. (' . $block_tags . ') # save tag name
  44. [^>]*>)
  45. | # match block close tag
  46. (</\s*(' . $block_tags . ')\s*>)
  47. )@smix';
  48.  
  49. $m = array();
  50.  
  51. preg_match_all($r, str_replace("\r", '', $s), $m, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
  52.  
  53. $matches = count($m);
  54.  
  55. $s = str_replace("\r", '', $s);
  56.  
  57. if ($matches == 0) {
  58. $buffer = "<p>" . linebreaker($s) . "</p>";
  59. return $buffer;
  60. } else {
  61. $p_parents = array('div'=>1, 'blockquote'=>1, 'td'=>1, 'th'=>1, 'ins'=>1, 'form'=>1, 'li'=>1);
  62. $buffer = '';
  63. $pre = false;
  64. $last_offset = 0;
  65. $tags = array();
  66. $tag = null;
  67. $tag_content = '';
  68. $reset_tag = null;
  69.  
  70. foreach ($m as $match) {
  71.  
  72. // grab the content from the latest match offset up to the current one
  73. $offset = $match[0][1];
  74. $slice = substr($s, $last_offset, $offset - $last_offset);
  75. $convert = is_null($tag) || (!$pre && isset($p_parents[$tag]));
  76. if ($convert) {
  77. $slice = trim($slice);
  78. $slice = linebreaker($slice);
  79. }
  80. $last_offset = $offset + strlen($match[0][0]);
  81.  
  82. // now fill the buffer
  83. if (!empty($slice))
  84. $buffer .= $convert ? "<p>$slice</p>\n" : "$slice";
  85.  
  86. // set the current tag context
  87. switch (count($match)) {
  88. case 2:
  89. # paragraph mark
  90. $buffer .= $pre ? "\n\n" : '';
  91. break;
  92. case 4:
  93. # block open tag
  94. $tag = strtolower($match[3][0]);
  95. $tags[] = $tag;
  96. if ($tag == 'pre' || $tag == 'script')
  97. $pre = true;
  98. $buffer .= $match[0][0] . ($pre ? '' : "\n");
  99. break;
  100. case 6:
  101. # block close tag
  102. array_pop($tags);
  103. $tag = strtolower($match[5][0]);
  104. if ($tag == 'pre' || $tag == 'script')
  105. $pre = false;
  106. $buffer .= $match[0][0] . ($pre ? '' : "\n");
  107. if ($tag == 'pre')
  108. $pre = false;
  109. $tlen = count($tags);
  110. if ($tlen > 0)
  111. $tag = $tags[$tlen - 1];
  112. else
  113. $tag = $pre = null;
  114. break;
  115. }
  116.  
  117. }
  118.  
  119. $tail = substr($s, $last_offset, strlen($s) - $last_offset);
  120. if ($pre) {
  121. // unlikely, but does not hurt to check
  122. $buffer .= $tail;
  123. } else {
  124. $tail = trim($tail);
  125. if (!empty($tail))
  126. $buffer .= '<p>' . linebreaker($tail) . '</p>';
  127. }
  128. }
  129.  
  130. return $buffer;
  131. }

URL: http://lightpress-de.googlecode.com/svn/trunk/lightpress/classes/Frontend.php

Report this snippet


Comments

RSS Icon Subscribe to comments

You need to login to post a comment.