--- /Users/jocrau/Downloads/typo3_src-4.1.6/typo3/sysext/cms/tslib/class.tslib_content.php +++ class.tslib_content_patched.php @@ -3605,25 +3605,81 @@ * @access private * @see stdWrap() */ - function crop($content,$options) { + function crop($content,$options) { $options = explode('|',$options); $chars = intval($options[0]); $afterstring = trim($options[1]); $crop2space = trim($options[2]); - if ($chars) { - if (strlen($content)>abs($chars)) { - if ($chars<0) { - $content = $GLOBALS['TSFE']->csConvObj->substr($GLOBALS['TSFE']->renderCharset,$content,$chars); - $trunc_at = strpos($content, ' '); - $content = ($trunc_at&&$crop2space) ? $afterstring.substr($content,$trunc_at) : $afterstring.$content; + $tags= 'a|b|blockquote|body|div|em|font|form|h1|h2|h3|h4|h5|h6|i|li|map|ol|option|p|pre|sub|sup|select|span|strong|table|td|textarea|tr|u|ul|br|hr|img|input|area|link'; + $regEx = '/(\<\/?(?:' . $tags . ')(?:\s*\>|\s[^\>]*\>))/si'; + $splittedContent = preg_split($regEx, $content, -1, PREG_SPLIT_DELIM_CAPTURE); + $strlen = 0; + // reverse array for 'back cropping' + $splittedContent = $chars < 0 ? array_reverse($splittedContent) : $splittedContent; + // crop the text (chars of a tag are not counted) + for ($offset=0; $offset < count($splittedContent); $offset++) { + if ($offset%2 === 0) { + $thisStrLen = $GLOBALS['TSFE']->csConvObj->strlen($GLOBALS['TSFE']->renderCharset, html_entity_decode($splittedContent[$offset],ENT_COMPAT,$GLOBALS['TSFE']->renderCharset)); + if (($strlen + $thisStrLen > abs($chars))) { + $croppedOffset = NULL; // offset of the content item which was cropped + if ($chars < 0) { + $cropPosition = $chars + $strlen; + $splittedContent[$offset] = $GLOBALS['TSFE']->csConvObj->substr($GLOBALS['TSFE']->renderCharset, $splittedContent[$offset], $cropPosition); + $truncatePosition = strpos($splittedContent[$offset], ' '); + $splittedContent[$offset] = $crop2space ? $afterstring . $GLOBALS['TSFE']->csConvObj->substr($GLOBALS['TSFE']->renderCharset, $splittedContent[$offset], (int)$truncatePosition) : $afterstring . $splittedContent[$offset]; + } else { + $cropPosition = $chars - $strlen; + $splittedContent[$offset] = $GLOBALS['TSFE']->csConvObj->substr($GLOBALS['TSFE']->renderCharset, $splittedContent[$offset], 0, $cropPosition); + $truncatePosition = strrpos($splittedContent[$offset], ' '); + $splittedContent[$offset] = $crop2space ? $GLOBALS['TSFE']->csConvObj->substr($GLOBALS['TSFE']->renderCharset, $splittedContent[$offset], 0, (int)$truncatePosition) . $afterstring : $splittedContent[$offset] . $afterstring; + } + // remember the $offset at which we cropped the content + $croppedOffset = $offset; + break; } else { - $content = $GLOBALS['TSFE']->csConvObj->substr($GLOBALS['TSFE']->renderCharset,$content,0,$chars); - $trunc_at = strrpos($content, ' '); - $content = ($trunc_at&&$crop2space) ? substr($content, 0, $trunc_at).$afterstring : $content.$afterstring; + $strlen += $thisStrLen; } } } - return $content; + + // close cropped tags + $closingTags = array(); + if($croppedOffset !== NULL) { + $tagName = ''; + $openingTagRegEx = '/^<([a-zA-Z0-6]+)(?:\s|>)/'; + $closingTagRegEx = '/^<\/([a-zA-Z0-6]+)(?:\s|>)/'; + for ($offset=$croppedOffset-1; $offset >= 0; $offset = $offset-2) { + if (preg_match('/\/\>$/',$splittedContent[$offset])) continue; // ignore empty element tags (e.g.
) + preg_match($chars<0?$closingTagRegEx:$openingTagRegEx, $splittedContent[$offset], $matches); + $tagName = $matches[1]; + // seek for the closing (or opening) tag + if (trim($tagName)!=='') { + $seekingTagName = ''; + for ($seekingOffset=$offset+2; $seekingOffset < count($splittedContent); $seekingOffset = $seekingOffset+2) { + preg_match($chars<0?$openingTagRegEx:$closingTagRegEx, $splittedContent[$seekingOffset], $matches); + $seekingTagName = $matches[1]; + if ($tagName === $seekingTagName) { // we found a matching tag + // add closing tag only if it occurs after the cropped content item + if ($seekingOffset > $croppedOffset) { + $closingTags[] = $splittedContent[$seekingOffset]; + } + break; + } + } + } + } + // drop the unnecessary items of the content array + array_splice($splittedContent,$croppedOffset+1); + } + + if ($chars < 0) { // reverse array for 'back cropping' + $splittedContent = array_merge($splittedContent,$closingTags); + $splittedContent = array_reverse($splittedContent); + } else { + $splittedContent = array_merge($splittedContent,$closingTags); + } + + return implode('',$splittedContent); } /**