Fixed word wrap in StringUtil::truncateHTML()
authorMarcel Werk <burntime@woltlab.com>
Fri, 25 Jan 2013 00:46:53 +0000 (01:46 +0100)
committerMarcel Werk <burntime@woltlab.com>
Fri, 25 Jan 2013 00:46:53 +0000 (01:46 +0100)
Fixes #1102

wcfsetup/install/files/lib/util/StringUtil.class.php

index 4add58c76000f01bac835ee9e3f4714f4c52bc64..bf1c8aa4146b9ab029648f7f1b2696e2535f709a 100644 (file)
@@ -591,8 +591,17 @@ final class StringUtil {
                        $truncatedString .= $tag[1];
        
                        // get length of the content without entities. If the content is too long, keep entities intact
-                       $contentLength = self::length(self::decodeHTML($tag[3]));
+                       $decodedContent = self::decodeHTML($tag[3]);
+                       $contentLength = self::length($decodedContent);
                        if ($contentLength + $totalLength > $length) {
+                               if ($wordWrap) {
+                                       if (preg_match('/^(.{1,'.($length - $totalLength).'}) /s', $decodedContent, $match)) {
+                                               $truncatedString .= StringUtil::encodeHTML($match[1]);
+                                       }
+                                       
+                                       break;
+                               }
+                               
                                $left = $length - $totalLength;
                                $entitiesLength = 0;
                                if (preg_match_all('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', $tag[3], $entities, PREG_OFFSET_CAPTURE)) {
@@ -618,37 +627,6 @@ final class StringUtil {
                        }
                }
        
-               // if word wrap is active search for the last word change
-               if ($wordWrap) {
-                       $lastWhitespace = self::lastIndexOf($truncatedString, ' ');
-                       // check if inside a tag
-                       $lastOpeningTag = self::lastIndexOf($truncatedString, '<');
-                       if ($lastOpeningTag < $lastWhitespace) {
-                               $lastClosingTag = self::lastIndexOf($truncatedString, '>');
-                               if (($lastClosingTag === false || $lastClosingTag > $lastWhitespace) && $lastClosingTag > $lastOpeningTag) {
-                                       $lastWhitespace = $lastOpeningTag;
-                                       array_shift($openTags);
-                                       if ($truncatedString[$lastWhitespace] != ' ') {
-                                               $firstPart = self::substring($truncatedString, 0, $lastWhitespace);
-                                               $secondPart = self::substring($truncatedString, $lastWhitespace + 1);
-                                               $truncatedString = $firstPart.' '.$secondPart;
-                                       }
-                               }
-                       }
-                       if ($lastWhitespace !== false) {
-                               $endString = self::substring($truncatedString, $lastWhitespace);
-                               preg_match_all('/<\/([a-z]+)>/', $endString, $tagOverhead, PREG_SET_ORDER);
-                               if (count($tagOverhead)) {
-                                       foreach ($tagOverhead as $tag) {
-                                               if (!in_array($tag[1], $openTags)) {
-                                                       array_unshift($openTags, $tag[1]);
-                                               }
-                                       }
-                               }
-                               $truncatedString = self::substring($truncatedString, 0, $lastWhitespace);
-                       }
-               }
-       
                // close all open tags
                foreach ($openTags as $tag) {
                        $truncatedString .= '</'.$tag.'>';