diff --git a/src/Umbraco.Core/Configuration/ClientDependencyConfiguration.cs b/src/Umbraco.Core/Configuration/ClientDependencyConfiguration.cs
index 6fbdec6901..62cd1ab59c 100644
--- a/src/Umbraco.Core/Configuration/ClientDependencyConfiguration.cs
+++ b/src/Umbraco.Core/Configuration/ClientDependencyConfiguration.cs
@@ -1,12 +1,19 @@
using System;
-using System.Linq;
+using System.Collections.Generic;
+using System.IO;
+using System.Web;
using System.Xml.Linq;
+using ClientDependency.Core.CompositeFiles.Providers;
+using ClientDependency.Core.Config;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Configuration
-{
- internal class ClientDependencyConfiguration
+{
+ ///
+ /// A utility class for working with CDF config and cache files - use sparingly!
+ ///
+ public class ClientDependencyConfiguration
{
private readonly ILogger _logger;
private readonly string _fileName;
@@ -21,7 +28,7 @@ namespace Umbraco.Core.Configuration
///
/// Changes the version number in ClientDependency.config to a random value to avoid stale caches
///
- internal bool IncreaseVersionNumber()
+ public bool IncreaseVersionNumber()
{
try
{
@@ -49,5 +56,55 @@ namespace Umbraco.Core.Configuration
return false;
}
+
+ ///
+ /// Clears the temporary files stored for the ClientDependency folder
+ ///
+ ///
+ public bool ClearTempFiles(HttpContextBase currentHttpContext)
+ {
+ var cdfTempDirectories = new HashSet();
+ foreach (BaseCompositeFileProcessingProvider provider in ClientDependencySettings.Instance
+ .CompositeFileProcessingProviderCollection)
+ {
+ var path = provider.CompositeFilePath.FullName;
+ cdfTempDirectories.Add(path);
+ }
+
+ try
+ {
+ var fullPath = currentHttpContext.Server.MapPath(XmlFileMapper.FileMapVirtualFolder);
+ if (fullPath != null)
+ {
+ cdfTempDirectories.Add(fullPath);
+ }
+ }
+ catch (Exception ex)
+ {
+ //invalid path format or something... try/catch to be safe
+ LogHelper.Error("Could not get path from ClientDependency.config", ex);
+ }
+
+ var success = true;
+ foreach (var directory in cdfTempDirectories)
+ {
+ var directoryInfo = new DirectoryInfo(directory);
+ if (directoryInfo.Exists == false)
+ continue;
+
+ try
+ {
+ directoryInfo.Delete(true);
+ }
+ catch (Exception ex)
+ {
+ // Something could be locking the directory or the was another error, making sure we don't break the upgrade installer
+ LogHelper.Error("Could not clear temp files", ex);
+ success = false;
+ }
+ }
+
+ return success;
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index c6e7692cee..680086b55f 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -45,6 +45,9 @@
..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll
True
+
+ ..\packages\ClientDependency.1.9.2\lib\net45\ClientDependency.Core.dll
+
..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll
True
diff --git a/src/Umbraco.Core/packages.config b/src/Umbraco.Core/packages.config
index c883ef1361..7c9fb9c19b 100644
--- a/src/Umbraco.Core/packages.config
+++ b/src/Umbraco.Core/packages.config
@@ -1,6 +1,7 @@
+
diff --git a/src/Umbraco.Tests/FrontEnd/UmbracoHelperTests.cs b/src/Umbraco.Tests/FrontEnd/UmbracoHelperTests.cs
index 672b9022e5..97f12cdaf8 100644
--- a/src/Umbraco.Tests/FrontEnd/UmbracoHelperTests.cs
+++ b/src/Umbraco.Tests/FrontEnd/UmbracoHelperTests.cs
@@ -21,6 +21,21 @@ namespace Umbraco.Tests.FrontEnd
Assert.AreEqual("Hello world, this is some…", result);
}
+ ///
+ /// If a truncated string ends with a space, we should trim the space before appending the ellipsis.
+ ///
+ [Test]
+ public void Truncate_Simple_With_Trimming()
+ {
+ var text = "Hello world, this is some text with a link";
+
+ var helper = new UmbracoHelper();
+
+ var result = helper.Truncate(text, 26).ToString();
+
+ Assert.AreEqual("Hello world, this is some…", result);
+ }
+
[Test]
public void Truncate_Inside_Word()
{
@@ -78,5 +93,79 @@ namespace Umbraco.Tests.FrontEnd
Assert.AreEqual(expectedResult, result);
}
+
+ [Test]
+ public void Truncate_By_Words()
+ {
+ var text = "Hello world, this is some text with a link";
+
+ var helper = new UmbracoHelper();
+
+ var result = helper.TruncateByWords(text, 4).ToString();
+
+ Assert.AreEqual("Hello world, this is…", result);
+ }
+
+ [Test]
+ public void Truncate_By_Words_With_Tag()
+ {
+ var text = "Hello world, this is some text with a link";
+
+ var helper = new UmbracoHelper();
+
+ var result = helper.TruncateByWords(text, 4).ToString();
+
+ Assert.AreEqual("Hello world, this is…", result);
+ }
+
+ [Test]
+ public void Truncate_By_Words_Mid_Tag()
+ {
+ var text = "Hello world, this is some text with a link";
+
+ var helper = new UmbracoHelper();
+
+ var result = helper.TruncateByWords(text, 7).ToString();
+
+ Assert.AreEqual("Hello world, this is some text with…", result);
+ }
+
+ [Test]
+ public void Strip_All_Html()
+ {
+ var text = "Hello world, this is some text with a link";
+
+ var helper = new UmbracoHelper();
+
+ var result = helper.StripHtml(text, null).ToString();
+
+ Assert.AreEqual("Hello world, this is some text with a link", result);
+ }
+
+ [Test]
+ public void Strip_Specific_Html()
+ {
+ var text = "Hello world, this is some text with a link";
+
+ string [] tags = {"b"};
+
+ var helper = new UmbracoHelper();
+
+ var result = helper.StripHtml(text, tags).ToString();
+
+ Assert.AreEqual("Hello world, this is some text with a link", result);
+ }
+
+ [Test]
+ public void Strip_Invalid_Html()
+ {
+ var text = "Hello world, is some text with a link";
+
+ var helper = new UmbracoHelper();
+
+ var result = helper.StripHtml(text).ToString();
+
+ Assert.AreEqual("Hello world, is some text with a link", result);
+ }
}
}
diff --git a/src/Umbraco.Web/HtmlStringUtilities.cs b/src/Umbraco.Web/HtmlStringUtilities.cs
index 11ba7a4d83..c4ae1c4eac 100644
--- a/src/Umbraco.Web/HtmlStringUtilities.cs
+++ b/src/Umbraco.Web/HtmlStringUtilities.cs
@@ -3,8 +3,10 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
+using System.Text.RegularExpressions;
using System.Web;
using HtmlAgilityPack;
+using Umbraco.Web.WebApi.Filters;
namespace Umbraco.Web
{
@@ -30,6 +32,7 @@ namespace Umbraco.Web
{
var doc = new HtmlDocument();
doc.LoadHtml("" + html + "
");
+
var targets = new List();
var nodes = doc.DocumentNode.FirstChild.SelectNodes(".//*");
@@ -55,7 +58,7 @@ namespace Umbraco.Web
{
return new HtmlString(html);
}
- return new HtmlString(doc.DocumentNode.FirstChild.InnerHtml);
+ return new HtmlString(doc.DocumentNode.FirstChild.InnerHtml.Replace(" ", " "));
}
internal string Join(string seperator, params object[] args)
@@ -85,6 +88,8 @@ namespace Umbraco.Web
public IHtmlString Truncate(string html, int length, bool addElipsis, bool treatTagsAsContent)
{
+ const string hellip = "…";
+
using (var outputms = new MemoryStream())
{
using (var outputtw = new StreamWriter(outputms))
@@ -106,7 +111,7 @@ namespace Umbraco.Web
isTagClose = false;
int ic = 0,
- currentLength = 0,
+ //currentLength = 0,
currentTextLength = 0;
string currentTag = string.Empty,
@@ -141,6 +146,10 @@ namespace Umbraco.Web
{
string thisTag = tagStack.Pop();
outputtw.Write("" + thisTag + ">");
+ if (treatTagsAsContent)
+ {
+ currentTextLength++;
+ }
}
if (!isTagClose && currentTag.Length > 0)
{
@@ -148,6 +157,10 @@ namespace Umbraco.Web
{
tagStack.Push(currentTag);
outputtw.Write("<" + currentTag);
+ if (treatTagsAsContent)
+ {
+ currentTextLength++;
+ }
if (!string.IsNullOrEmpty(tagContents))
{
if (tagContents.EndsWith("/"))
@@ -205,7 +218,7 @@ namespace Umbraco.Web
{
var charToWrite = (char)ic;
outputtw.Write(charToWrite);
- currentLength++;
+ //currentLength++;
}
}
@@ -221,7 +234,7 @@ namespace Umbraco.Web
// Reached truncate limit.
if (addElipsis)
{
- outputtw.Write("…");
+ outputtw.Write(hellip);
}
lengthReached = true;
}
@@ -235,10 +248,59 @@ namespace Umbraco.Web
outputms.Position = 0;
using (TextReader outputtr = new StreamReader(outputms))
{
- return new HtmlString(outputtr.ReadToEnd().Replace(" ", " ").Trim());
+ string result = string.Empty;
+
+ string firstTrim = outputtr.ReadToEnd().Replace(" ", " ").Trim();
+
+ //Check to see if there is an empty char between the hellip and the output string
+ //if there is, remove it
+ if (string.IsNullOrWhiteSpace(firstTrim) == false)
+ {
+ result = firstTrim[firstTrim.Length - hellip.Length - 1] == ' ' ? firstTrim.Remove(firstTrim.Length - hellip.Length - 1, 1) : firstTrim;
+ }
+ return new HtmlString(result);
}
}
}
}
+
+ ///
+ /// Returns the length of the words from a html block
+ ///
+ /// Html text
+ /// Amount of words you would like to measure
+ ///
+ ///
+ public int WordsToLength(string html, int words)
+ {
+ HtmlDocument doc = new HtmlDocument();
+ doc.LoadHtml(html);
+
+ int wordCount = 0,
+ length = 0,
+ maxWords = words;
+
+ html = StripHtmlTags(html, null).ToString();
+
+ while (length < html.Length)
+ {
+ // Check to see if the current wordCount reached the maxWords allowed
+ if (wordCount.Equals(maxWords)) break;
+ // Check if current char is part of a word
+ while (length < html.Length && char.IsWhiteSpace(html[length]) == false)
+ {
+ length++;
+ }
+
+ wordCount++;
+
+ // Skip whitespace until the next word
+ while (length < html.Length && char.IsWhiteSpace(html[length]) && wordCount.Equals(maxWords) == false)
+ {
+ length++;
+ }
+ }
+ return length;
+ }
}
}
diff --git a/src/Umbraco.Web/Install/Controllers/InstallController.cs b/src/Umbraco.Web/Install/Controllers/InstallController.cs
index 360e35efda..7e3336e1e8 100644
--- a/src/Umbraco.Web/Install/Controllers/InstallController.cs
+++ b/src/Umbraco.Web/Install/Controllers/InstallController.cs
@@ -47,6 +47,8 @@ namespace Umbraco.Web.Install.Controllers
// Update ClientDependency version
var clientDependencyConfig = new ClientDependencyConfiguration(ApplicationContext.Current.ProfilingLogger.Logger);
var clientDependencyUpdated = clientDependencyConfig.IncreaseVersionNumber();
+ // Delete ClientDependency temp directories to make sure we get fresh caches
+ var clientDependencyTempFilesDeleted = clientDependencyConfig.ClearTempFiles(HttpContext);
var result = _umbracoContext.Security.ValidateCurrentUser(false);
diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs
index 40126a175f..d94476b31c 100644
--- a/src/Umbraco.Web/UmbracoHelper.cs
+++ b/src/Umbraco.Web/UmbracoHelper.cs
@@ -1439,18 +1439,58 @@ namespace Umbraco.Web
///
public IHtmlString Truncate(string html, int length, bool addElipsis, bool treatTagsAsContent)
{
- return _stringUtilities.Truncate(html, length, addElipsis, treatTagsAsContent);
- }
+ return _stringUtilities.Truncate(html, length, addElipsis, treatTagsAsContent);
+ }
+ #region Truncate by Words
+ ///
+ /// Truncates a string to a given amount of words, can add a elipsis at the end (...). Method checks for open html tags, and makes sure to close them
+ ///
+ public IHtmlString TruncateByWords(string html, int words)
+ {
+ int length = _stringUtilities.WordsToLength(html, words);
- #endregion
+ return Truncate(html, length, true, false);
+ }
- #region If
+ ///
+ /// Truncates a string to a given amount of words, can add a elipsis at the end (...). Method checks for open html tags, and makes sure to close them
+ ///
+ public IHtmlString TruncateByWords(string html, int words, bool addElipsis)
+ {
+ int length = _stringUtilities.WordsToLength(html, words);
- ///
- /// If the test is true, the string valueIfTrue will be returned, otherwise the valueIfFalse will be returned.
- ///
- public HtmlString If(bool test, string valueIfTrue, string valueIfFalse)
+ return Truncate(html, length, addElipsis, false);
+ }
+
+ ///
+ /// Truncates a string to a given amount of words, can add a elipsis at the end (...). Method checks for open html tags, and makes sure to close them
+ ///
+ public IHtmlString TruncateByWords(IHtmlString html, int words)
+ {
+ int length = _stringUtilities.WordsToLength(html.ToHtmlString(), words);
+
+ return Truncate(html, length, true, false);
+ }
+
+ ///
+ /// Truncates a string to a given amount of words, can add a elipsis at the end (...). Method checks for open html tags, and makes sure to close them
+ ///
+ public IHtmlString TruncateByWords(IHtmlString html, int words, bool addElipsis)
+ {
+ int length = _stringUtilities.WordsToLength(html.ToHtmlString(), words);
+
+ return Truncate(html, length, addElipsis, false);
+ }
+ #endregion
+ #endregion
+
+ #region If
+
+ ///
+ /// If the test is true, the string valueIfTrue will be returned, otherwise the valueIfFalse will be returned.
+ ///
+ public HtmlString If(bool test, string valueIfTrue, string valueIfFalse)
{
return test ? new HtmlString(valueIfTrue) : new HtmlString(valueIfFalse);
}