PageRenderTime 42ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/smarty/plugins/modifier.truncate.php

https://github.com/michaeljoyce/pkp-lib
PHP | 244 lines | 143 code | 26 blank | 75 comment | 52 complexity | a036dbda63f9b8e44ca5b1a31f4702d4 MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause
  1. <?php
  2. /**
  3. * Smarty plugin
  4. * @package Smarty
  5. * @subpackage plugins
  6. */
  7. /**
  8. * Smarty truncate modifier plugin
  9. *
  10. * Type: modifier<br>
  11. * Name: truncate<br>
  12. * Purpose: Truncate a string to a certain length if necessary,
  13. * optionally splitting in the middle of a word, and
  14. * appending the $etc string or inserting $etc into the middle.
  15. * @link http://smarty.php.net/manual/en/language.modifier.truncate.php
  16. * truncate (Smarty online manual)
  17. * @author Monte Ohrt <monte at ohrt dot com> with modifications by Matthew Crider (mcrider at sfu dot ca)
  18. * @param string
  19. * @param integer
  20. * @param string
  21. * @param boolean
  22. * @param boolean
  23. * @param boolean
  24. * @return string
  25. */
  26. function smarty_modifier_truncate($string, $length = 80, $etc = '...',
  27. $break_words = false, $middle = false, $skip_tags = true)
  28. {
  29. if ($length == 0)
  30. return '';
  31. if (strlen($string) > $length) {
  32. $originalLength = strlen($string);
  33. if($skip_tags) {
  34. if ($middle) {
  35. $tagsReverse = array();
  36. remove_tags($string, $tagsReverse, true, $length);
  37. }
  38. $tags = array();
  39. $string = remove_tags($string, $tags, false, $length);
  40. }
  41. $length -= min($length, strlen($etc));
  42. if (!$middle) {
  43. if(!$break_words) {
  44. $string = preg_replace('/\s+?(\S+)?$/', '', substr($string, 0, $length+1));
  45. } else $string = substr($string, 0, $length+1);
  46. if($skip_tags) $string = reinsert_tags($string, $tags);
  47. return close_tags($string) . $etc;
  48. }
  49. else {
  50. $firstHalf = substr($string, 0, $length/2);
  51. $secondHalf = substr($string, -$length/2);
  52. if($break_words) {
  53. if($skip_tags) {
  54. $firstHalf = reinsert_tags($firstHalf, $tags);
  55. $secondHalf = reinsert_tags($secondHalf, $tagsReverse, true);
  56. return close_tags($firstHalf) . $etc . close_tags($secondHalf, true);
  57. } else {
  58. return $firstHalf . $etc . $secondHalf;
  59. }
  60. } else {
  61. for($i=$length/2; $string[$i] != ' '; $i++) {
  62. $firstHalf = substr($string, 0, $i+1);
  63. }
  64. for($i=$length/2; substr($string, -$i, 1) != ' '; $i++) {
  65. $secondHalf = substr($string, -$i-1);
  66. }
  67. if($skip_tags) {
  68. $firstHalf = reinsert_tags($firstHalf, $tags);
  69. $secondHalf = reinsert_tags($secondHalf, $tagsReverse, strlen($string));
  70. return close_tags($firstHalf) . $etc . close_tags($secondHalf, true);
  71. } else {
  72. return $firstHalf . $etc . $secondHalf;
  73. }
  74. }
  75. }
  76. } else {
  77. return $string;
  78. }
  79. }
  80. /**
  81. * Helper function: Remove XHTML tags and insert them into a global array along with their position
  82. * @author Matt Crider
  83. * @param string
  84. * @param array
  85. * @param boolean
  86. * @param int
  87. * @return string
  88. */
  89. function remove_tags($string, &$tags, $reverse = false, $length) {
  90. if($reverse) {
  91. return remove_tags_aux_reverse($string, 0, $tags, $length);
  92. } else return remove_tags_aux($string, 0, $tags, $length);
  93. }
  94. /**
  95. * Helper function: Recursive function called by remove_tags
  96. * @author Matt Crider
  97. * @param string
  98. * @param int
  99. * @param array
  100. * @param int
  101. * @return string
  102. */
  103. function remove_tags_aux($string, $loc, &$tags, $length) {
  104. if(strlen($string) > 0 && $length > 0) {
  105. $length--;
  106. if($string[0] == '<') {
  107. $closeBrack = strpos($string, '>')+1;
  108. if($closeBrack) {
  109. $tags[] = array(substr($string, 0, $closeBrack), $loc);
  110. return remove_tags_aux(substr($string, $closeBrack), $loc+$closeBrack, $tags, $length);
  111. }
  112. }
  113. return $string[0] . remove_tags_aux(substr($string, 1), $loc+1, $tags, $length);
  114. }
  115. }
  116. /**
  117. * Helper function: Recursive function called by remove_tags
  118. * Removes tags from the back of the string and keeps a record of their position from the back
  119. * @author Matt Crider
  120. * @param string
  121. * @param int loc Keeps track of position from the back of original string
  122. * @param array
  123. * @param int
  124. * @return string
  125. */
  126. function remove_tags_aux_reverse($string, $loc, &$tags, $length) {
  127. $backLoc = strlen($string)-1;
  128. if($backLoc >= 0 && $length > 0) {
  129. $length--;
  130. if($string[$backLoc] == '>') {
  131. $tag = '>';
  132. $openBrack = 1;
  133. while ($string[$backLoc-$openBrack] != '<') {
  134. $tag = $string[$backLoc-$openBrack] . $tag;
  135. $openBrack++;
  136. }
  137. $tag = '<' . $tag;
  138. $openBrack++;
  139. $tags[] = array($tag, $loc);
  140. //echo "loc: " . $loc . "\n";
  141. //echo "openBrack: " . $openBrack . "\n";
  142. return remove_tags_aux_reverse(substr($string, 0, -$openBrack), $loc+$openBrack, $tags, $length);
  143. }
  144. return remove_tags_aux_reverse(substr($string, 0, -1), $loc+1, $tags, $length) . $string[$backLoc];
  145. }
  146. }
  147. /**
  148. * Helper function: Reinsert tags from the tag array into their original position in the string
  149. * @author Matt Crider
  150. * @param string
  151. * @param array
  152. * @param boolean Set to true to reinsert tags starting at the back of the string
  153. * @return string
  154. */
  155. function reinsert_tags($string, &$tags, $reverse = false) {
  156. if(empty($tags)) return $string;
  157. for($i = 0; $i < count($tags); $i++) {
  158. $length = strlen($string);
  159. if ($tags[$i][1] < strlen($string)) {
  160. if ($reverse) {
  161. if ($tags[$i][1] == 0) { // Cannot use -0 as the start index (its same as +0)
  162. $string = substr_replace($string, $tags[$i][0], $length, 0);
  163. } else {
  164. $string = substr_replace($string, $tags[$i][0], -$tags[$i][1], 0);
  165. }
  166. } else {
  167. $string = substr_replace($string, $tags[$i][0], $tags[$i][1], 0);
  168. }
  169. }
  170. }
  171. return $string;
  172. }
  173. /**
  174. * Helper function: Closes all dangling XHTML tags in a string
  175. * Modified from http://milianw.de/code-snippets/close-html-tags
  176. * by Milian Wolff <mail@milianw.de>
  177. * @param string
  178. * @return string
  179. */
  180. function close_tags($string, $open = false){
  181. //put all opened tags into an array
  182. preg_match_all("#<([a-z]+)( .*)?(?!/)>#iU",$string,$result);
  183. $openedtags=$result[1];
  184. //put all closed tags into an array
  185. preg_match_all("#</([a-z]+)>#iU",$string,$result);
  186. $closedtags = $result[1];
  187. $len_opened = count($openedtags);
  188. $len_closed = count($closedtags);
  189. // all tags are closed
  190. if(count($closedtags) == $len_opened){
  191. return $string;
  192. }
  193. $openedtags = array_reverse($openedtags);
  194. $closedtags = array_reverse($closedtags);
  195. if ($open) {
  196. //open tags
  197. for($i=0; $i < $len_closed; $i++) {
  198. if (!in_array($closedtags[$i],$openedtags)){
  199. $string = '<'.$closedtags[$i].'>' . $string;
  200. } else {
  201. unset($openedtags[array_search($closedtags[$i],$openedtags)]);
  202. }
  203. }
  204. return $string;
  205. } else {
  206. // close tags
  207. for($i=0; $i < $len_opened; $i++) {
  208. if (!in_array($openedtags[$i],$closedtags)){
  209. $string .= '</'.$openedtags[$i].'>';
  210. } else {
  211. unset($closedtags[array_search($openedtags[$i],$closedtags)]);
  212. }
  213. }
  214. return $string;
  215. }
  216. }
  217. /* vim: set expandtab: */
  218. ?>