From 34b524aabb6085616e1c101557d3a18b72d89c78 Mon Sep 17 00:00:00 2001 From: chrisjsherm Date: Fri, 19 Dec 2014 17:47:12 -0500 Subject: [PATCH] Fix for Truncate function stripping out content between tags. This issue is referenced at issues.umbraco.org/issue/U4-4158. --- src/Umbraco.Web/UmbracoHelper.cs | 271 ++++++++++++++++--------------- 1 file changed, 137 insertions(+), 134 deletions(-) diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs index 81b443a265..c6c44e1a45 100644 --- a/src/Umbraco.Web/UmbracoHelper.cs +++ b/src/Umbraco.Web/UmbracoHelper.cs @@ -1140,143 +1140,146 @@ namespace Umbraco.Web } public IHtmlString Truncate(string html, int length, bool addElipsis, bool treatTagsAsContent) { - using (var outputms = new MemoryStream()) - { - using (var outputtw = new StreamWriter(outputms)) - { - using (var ms = new MemoryStream()) - { - using (var tw = new StreamWriter(ms)) - { - tw.Write(html); - tw.Flush(); - ms.Position = 0; - var tagStack = new Stack(); - using (TextReader tr = new StreamReader(ms)) - { - bool IsInsideElement = false; - bool lengthReached = false; - int ic = 0; - int currentLength = 0, currentTextLength = 0; - string currentTag = string.Empty; - string tagContents = string.Empty; - bool insideTagSpaceEncountered = false; - bool isTagClose = false; - while ((ic = tr.Read()) != -1) - { - bool write = true; + using (var outputms = new MemoryStream()) + { + using (var outputtw = new StreamWriter(outputms)) + { + using (var ms = new MemoryStream()) + { + using (var tw = new StreamWriter(ms)) + { + tw.Write(html); + tw.Flush(); + ms.Position = 0; + var tagStack = new Stack(); - if (ic == (int)'<') - { - if (!lengthReached) - { - IsInsideElement = true; - } - insideTagSpaceEncountered = false; - currentTag = string.Empty; - tagContents = string.Empty; - isTagClose = false; - if (tr.Peek() == (int)'/') - { - isTagClose = true; - } - } - else if (ic == (int)'>') - { - //if (IsInsideElement) - //{ - IsInsideElement = false; - //if (write) - //{ - // outputtw.Write('>'); - //} - currentTextLength++; - if (isTagClose && tagStack.Count > 0) - { - string thisTag = tagStack.Pop(); - outputtw.Write(""); - } - if (!isTagClose && currentTag.Length > 0) - { - if (!lengthReached) - { - tagStack.Push(currentTag); - outputtw.Write("<" + currentTag); - if (tr.Peek() != (int)' ') - { - if (!string.IsNullOrEmpty(tagContents)) - { - if (tagContents.EndsWith("/")) - { - //short close - tagStack.Pop(); - } - outputtw.Write(tagContents); - } - outputtw.Write(">"); - } - } - } - //} - continue; - } - else - { - if (IsInsideElement) - { - if (ic == (int)' ') - { - if (!insideTagSpaceEncountered) - { - insideTagSpaceEncountered = true; - //if (!isTagClose) - //{ - // tagStack.Push(currentTag); - //} - } - } - if (!insideTagSpaceEncountered) - { - currentTag += (char)ic; - } - } - } - if (IsInsideElement || insideTagSpaceEncountered) - { - write = false; - if (insideTagSpaceEncountered) - { - tagContents += (char)ic; - } - } - if (!IsInsideElement || treatTagsAsContent) - { - currentTextLength++; - } - currentLength++; - if (currentTextLength <= length || (lengthReached && IsInsideElement)) - { - if (write) - { - outputtw.Write((char)ic); - } - } - if (!lengthReached && currentTextLength >= length) - { - //reached truncate point - if (addElipsis) - { - outputtw.Write("…"); - } - lengthReached = true; - } + using (TextReader tr = new StreamReader(ms)) + { + bool isInsideElement = false, + lengthReached = false, + insideTagSpaceEncountered = false, + isTagClose = false; - } + int ic = 0, + currentLength = 0, + currentTextLength = 0; - } - } - } - outputtw.Flush(); + string currentTag = string.Empty, + tagContents = string.Empty; + + while ((ic = tr.Read()) != -1) + { + bool write = true; + + switch ((char)ic) + { + case '<': + if (!lengthReached) + { + isInsideElement = true; + } + + insideTagSpaceEncountered = false; + currentTag = string.Empty; + tagContents = string.Empty; + isTagClose = false; + if (tr.Peek() == (int)'/') + { + isTagClose = true; + } + break; + + case '>': + isInsideElement = false; + + if (isTagClose && tagStack.Count > 0) + { + string thisTag = tagStack.Pop(); + outputtw.Write(""); + } + if (!isTagClose && currentTag.Length > 0) + { + if (!lengthReached) + { + tagStack.Push(currentTag); + outputtw.Write("<" + currentTag); + if (!string.IsNullOrEmpty(tagContents)) + { + if (tagContents.EndsWith("/")) + { + // No end tag e.g.
. + tagStack.Pop(); + } + + outputtw.Write(tagContents); + write = true; + insideTagSpaceEncountered = false; + } + outputtw.Write(">"); + } + } + // Continue to next iteration of the text reader. + continue; + + default: + if (isInsideElement) + { + if (ic == (int)' ') + { + if (!insideTagSpaceEncountered) + { + insideTagSpaceEncountered = true; + } + } + + if (!insideTagSpaceEncountered) + { + currentTag += (char)ic; + } + } + break; + } + + if (isInsideElement || insideTagSpaceEncountered) + { + write = false; + if (insideTagSpaceEncountered) + { + tagContents += (char)ic; + } + } + + if (!isInsideElement || treatTagsAsContent) + { + currentTextLength++; + } + + if (currentTextLength <= length || (lengthReached && isInsideElement)) + { + if (write) + { + var charToWrite = (char)ic; + outputtw.Write(charToWrite); + currentLength++; + } + } + + if (!lengthReached && currentTextLength >= length) + { + // Reached truncate limit. + if (addElipsis) + { + outputtw.Write("…"); + } + lengthReached = true; + } + + } + + } + } + } + outputtw.Flush(); outputms.Position = 0; using (TextReader outputtr = new StreamReader(outputms)) {