Merge
This commit is contained in:
@@ -21,7 +21,6 @@ namespace Umbraco.Core
|
||||
///</summary>
|
||||
public static class StringExtensions
|
||||
{
|
||||
|
||||
public const string UmbracoValidAliasCharacters = "_-abcdefghijklmnopqrstuvwxyz1234567890";
|
||||
public const string UmbracoInvalidFirstCharacters = "01234567890";
|
||||
|
||||
@@ -61,7 +60,8 @@ namespace Umbraco.Core
|
||||
|
||||
return encrpytedValue.ToString().TrimEnd();
|
||||
}
|
||||
/// <summary>
|
||||
|
||||
/// <summary>
|
||||
/// Decrypt the encrypted string using the Machine key in medium trust
|
||||
/// </summary>
|
||||
/// <param name="value">The string value to be decrypted</param>
|
||||
@@ -82,6 +82,7 @@ namespace Umbraco.Core
|
||||
|
||||
return decryptedValue.ToString();
|
||||
}
|
||||
|
||||
//this is from SqlMetal and just makes it a bit of fun to allow pluralisation
|
||||
public static string MakePluralName(this string name)
|
||||
{
|
||||
@@ -301,151 +302,6 @@ namespace Umbraco.Core
|
||||
return Regex.Replace(text, pattern, String.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts string to a URL alias.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="charReplacements">The char replacements.</param>
|
||||
/// <param name="replaceDoubleDashes">if set to <c>true</c> replace double dashes.</param>
|
||||
/// <param name="stripNonAscii">if set to <c>true</c> strip non ASCII.</param>
|
||||
/// <param name="urlEncode">if set to <c>true</c> URL encode.</param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This ensures that ONLY ascii chars are allowed and of those ascii chars, only digits and lowercase chars, all
|
||||
/// punctuation, etc... are stripped out, however this method allows you to pass in string's to replace with the
|
||||
/// specified replacement character before the string is converted to ascii and it has invalid characters stripped out.
|
||||
/// This allows you to replace strings like & , etc.. with your replacement character before the automatic
|
||||
/// reduction.
|
||||
/// </remarks>
|
||||
public static string ToUrlAlias(this string value, IDictionary<string, string> charReplacements, bool replaceDoubleDashes, bool stripNonAscii, bool urlEncode)
|
||||
{
|
||||
//first to lower case
|
||||
value = value.ToLowerInvariant();
|
||||
|
||||
//then replacement chars
|
||||
value = charReplacements.Aggregate(value, (current, kvp) => current.Replace(kvp.Key, kvp.Value));
|
||||
|
||||
//then convert to only ascii, this will remove the rest of any invalid chars
|
||||
if (stripNonAscii)
|
||||
{
|
||||
value = Encoding.ASCII.GetString(
|
||||
Encoding.Convert(
|
||||
Encoding.UTF8,
|
||||
Encoding.GetEncoding(
|
||||
Encoding.ASCII.EncodingName,
|
||||
new EncoderReplacementFallback(String.Empty),
|
||||
new DecoderExceptionFallback()),
|
||||
Encoding.UTF8.GetBytes(value)));
|
||||
|
||||
//remove all characters that do not fall into the following categories (apart from the replacement val)
|
||||
var validCodeRanges =
|
||||
//digits
|
||||
Enumerable.Range(48, 10).Concat(
|
||||
//lowercase chars
|
||||
Enumerable.Range(97, 26));
|
||||
|
||||
var sb = new StringBuilder();
|
||||
foreach (var c in value.Where(c => charReplacements.Values.Contains(c.ToString()) || validCodeRanges.Contains(c)))
|
||||
{
|
||||
sb.Append(c);
|
||||
}
|
||||
|
||||
value = sb.ToString();
|
||||
}
|
||||
|
||||
//trim dashes from end
|
||||
value = value.Trim('-', '_');
|
||||
|
||||
//replace double occurances of - or _
|
||||
value = replaceDoubleDashes ? Regex.Replace(value, @"([-_]){2,}", "$1", RegexOptions.Compiled) : value;
|
||||
|
||||
//url encode result
|
||||
return urlEncode ? HttpUtility.UrlEncode(value) : value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a string for use with an entity alias which is camel case and without invalid characters
|
||||
/// </summary>
|
||||
/// <param name="phrase">The phrase.</param>
|
||||
/// <param name="caseType">By default this is camel case</param>
|
||||
/// <param name="removeSpaces">if set to <c>true</c> [remove spaces].</param>
|
||||
/// <returns></returns>
|
||||
public static string ToUmbracoAlias(this string phrase, StringAliasCaseType caseType = StringAliasCaseType.CamelCase, bool removeSpaces = false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(phrase)) return string.Empty;
|
||||
|
||||
//convert case first
|
||||
var tmp = phrase.ConvertCase(caseType);
|
||||
|
||||
//remove non-alphanumeric chars
|
||||
var result = Regex.Replace(tmp, @"[^a-zA-Z0-9\s\.-]+", "", RegexOptions.Compiled);
|
||||
|
||||
if (removeSpaces)
|
||||
result = result.Replace(" ", "");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits a Pascal cased string into a phrase seperated by spaces.
|
||||
/// </summary>
|
||||
/// <param name="phrase">String to split</param>
|
||||
/// <returns></returns>
|
||||
public static string SplitPascalCasing(this string phrase)
|
||||
{
|
||||
string result = Regex.Replace(phrase, "([a-z](?=[A-Z])|[A-Z](?=[A-Z][a-z]))", "$1 ");
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the phrase to specified convention.
|
||||
/// </summary>
|
||||
/// <param name="phrase"></param>
|
||||
/// <param name="cases">The cases.</param>
|
||||
/// <returns>string</returns>
|
||||
public static string ConvertCase(this string phrase, StringAliasCaseType cases)
|
||||
{
|
||||
var splittedPhrase = Regex.Split(phrase, @"[^a-zA-Z0-9\']", RegexOptions.Compiled);
|
||||
|
||||
if (cases == StringAliasCaseType.Unchanged)
|
||||
return string.Join("", splittedPhrase);
|
||||
|
||||
//var splittedPhrase = phrase.Split(' ', '-', '.');
|
||||
var sb = new StringBuilder();
|
||||
|
||||
foreach (var splittedPhraseChars in splittedPhrase.Select(s => s.ToCharArray()))
|
||||
{
|
||||
if (splittedPhraseChars.Length > 0)
|
||||
{
|
||||
splittedPhraseChars[0] = ((new String(splittedPhraseChars[0], 1)).ToUpper().ToCharArray())[0];
|
||||
}
|
||||
sb.Append(new String(splittedPhraseChars));
|
||||
}
|
||||
|
||||
var result = sb.ToString();
|
||||
|
||||
if (cases == StringAliasCaseType.CamelCase)
|
||||
{
|
||||
if (result.Length > 1)
|
||||
{
|
||||
var pattern = new Regex("^([A-Z]*)([A-Z].*)$", RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
var match = pattern.Match(result);
|
||||
if (match.Success)
|
||||
{
|
||||
result = match.Groups[1].Value.ToLower() + match.Groups[2].Value;
|
||||
|
||||
return result.Substring(0, 1).ToLower() + result.Substring(1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return result.ToLower();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encodes as GUID.
|
||||
/// </summary>
|
||||
@@ -803,6 +659,70 @@ namespace Umbraco.Core
|
||||
: alternative;
|
||||
}
|
||||
|
||||
// FORMAT STRINGS
|
||||
|
||||
/// <summary>
|
||||
/// Converts string to a URL alias.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="charReplacements">The char replacements.</param>
|
||||
/// <param name="replaceDoubleDashes">if set to <c>true</c> replace double dashes.</param>
|
||||
/// <param name="stripNonAscii">if set to <c>true</c> strip non ASCII.</param>
|
||||
/// <param name="urlEncode">if set to <c>true</c> URL encode.</param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This ensures that ONLY ascii chars are allowed and of those ascii chars, only digits and lowercase chars, all
|
||||
/// punctuation, etc... are stripped out, however this method allows you to pass in string's to replace with the
|
||||
/// specified replacement character before the string is converted to ascii and it has invalid characters stripped out.
|
||||
/// This allows you to replace strings like & , etc.. with your replacement character before the automatic
|
||||
/// reduction.
|
||||
/// </remarks>
|
||||
public static string ToUrlAlias(this string value, IDictionary<string, string> charReplacements, bool replaceDoubleDashes, bool stripNonAscii, bool urlEncode)
|
||||
{
|
||||
//first to lower case
|
||||
value = value.ToLowerInvariant();
|
||||
|
||||
//then replacement chars
|
||||
value = charReplacements.Aggregate(value, (current, kvp) => current.Replace(kvp.Key, kvp.Value));
|
||||
|
||||
//then convert to only ascii, this will remove the rest of any invalid chars
|
||||
if (stripNonAscii)
|
||||
{
|
||||
value = Encoding.ASCII.GetString(
|
||||
Encoding.Convert(
|
||||
Encoding.UTF8,
|
||||
Encoding.GetEncoding(
|
||||
Encoding.ASCII.EncodingName,
|
||||
new EncoderReplacementFallback(String.Empty),
|
||||
new DecoderExceptionFallback()),
|
||||
Encoding.UTF8.GetBytes(value)));
|
||||
|
||||
//remove all characters that do not fall into the following categories (apart from the replacement val)
|
||||
var validCodeRanges =
|
||||
//digits
|
||||
Enumerable.Range(48, 10).Concat(
|
||||
//lowercase chars
|
||||
Enumerable.Range(97, 26));
|
||||
|
||||
var sb = new StringBuilder();
|
||||
foreach (var c in value.Where(c => charReplacements.Values.Contains(c.ToString()) || validCodeRanges.Contains(c)))
|
||||
{
|
||||
sb.Append(c);
|
||||
}
|
||||
|
||||
value = sb.ToString();
|
||||
}
|
||||
|
||||
//trim dashes from end
|
||||
value = value.Trim('-', '_');
|
||||
|
||||
//replace double occurances of - or _
|
||||
value = replaceDoubleDashes ? Regex.Replace(value, @"([-_]){2,}", "$1", RegexOptions.Compiled) : value;
|
||||
|
||||
//url encode result
|
||||
return urlEncode ? HttpUtility.UrlEncode(value) : value;
|
||||
}
|
||||
|
||||
public static string FormatUrl(this string url)
|
||||
{
|
||||
string newUrl = url;
|
||||
@@ -870,5 +790,89 @@ namespace Umbraco.Core
|
||||
|
||||
return alias;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a string for use with an entity alias which is camel case and without invalid characters
|
||||
/// </summary>
|
||||
/// <param name="phrase">The phrase.</param>
|
||||
/// <param name="caseType">By default this is camel case</param>
|
||||
/// <param name="removeSpaces">if set to <c>true</c> [remove spaces].</param>
|
||||
/// <returns></returns>
|
||||
public static string ToUmbracoAlias(this string phrase, StringAliasCaseType caseType = StringAliasCaseType.CamelCase, bool removeSpaces = false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(phrase)) return string.Empty;
|
||||
|
||||
//convert case first
|
||||
var tmp = phrase.ConvertCase(caseType);
|
||||
|
||||
//remove non-alphanumeric chars
|
||||
var result = Regex.Replace(tmp, @"[^a-zA-Z0-9\s\.-]+", "", RegexOptions.Compiled);
|
||||
|
||||
if (removeSpaces)
|
||||
result = result.Replace(" ", "");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the phrase to specified convention.
|
||||
/// </summary>
|
||||
/// <param name="phrase"></param>
|
||||
/// <param name="cases">The cases.</param>
|
||||
/// <returns>string</returns>
|
||||
public static string ConvertCase(this string phrase, StringAliasCaseType cases)
|
||||
{
|
||||
var splittedPhrase = Regex.Split(phrase, @"[^a-zA-Z0-9\']", RegexOptions.Compiled);
|
||||
|
||||
if (cases == StringAliasCaseType.Unchanged)
|
||||
return string.Join("", splittedPhrase);
|
||||
|
||||
//var splittedPhrase = phrase.Split(' ', '-', '.');
|
||||
var sb = new StringBuilder();
|
||||
|
||||
foreach (var splittedPhraseChars in splittedPhrase.Select(s => s.ToCharArray()))
|
||||
{
|
||||
if (splittedPhraseChars.Length > 0)
|
||||
{
|
||||
splittedPhraseChars[0] = ((new String(splittedPhraseChars[0], 1)).ToUpper().ToCharArray())[0];
|
||||
}
|
||||
sb.Append(new String(splittedPhraseChars));
|
||||
}
|
||||
|
||||
var result = sb.ToString();
|
||||
|
||||
if (cases == StringAliasCaseType.CamelCase)
|
||||
{
|
||||
if (result.Length > 1)
|
||||
{
|
||||
var pattern = new Regex("^([A-Z]*)([A-Z].*)$", RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
var match = pattern.Match(result);
|
||||
if (match.Success)
|
||||
{
|
||||
result = match.Groups[1].Value.ToLower() + match.Groups[2].Value;
|
||||
|
||||
return result.Substring(0, 1).ToLower() + result.Substring(1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return result.ToLower();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits a Pascal cased string into a phrase seperated by spaces.
|
||||
/// </summary>
|
||||
/// <param name="phrase">String to split</param>
|
||||
/// <returns></returns>
|
||||
public static string SplitPascalCasing(this string phrase)
|
||||
{
|
||||
string result = Regex.Replace(phrase, "([a-z](?=[A-Z])|[A-Z](?=[A-Z][a-z]))", "$1 ");
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,8 @@ namespace Umbraco.Tests.ContentStores
|
||||
</Home>
|
||||
<Home id=""1175"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""1045"" sortOrder=""2"" createDate=""2012-07-20T18:08:01"" updateDate=""2012-07-20T18:49:32"" nodeName=""Sub 2"" urlName=""sub-2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1175"" isDoc=""""><content><![CDATA[]]></content>
|
||||
</Home>
|
||||
<Home id=""1177"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""1045"" sortOrder=""2"" createDate=""2012-07-20T18:08:01"" updateDate=""2012-07-20T18:49:32"" nodeName=""Sub'Apostrophe"" urlName=""sub'apostrophe"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1177"" isDoc=""""><content><![CDATA[]]></content>
|
||||
</Home>
|
||||
</Home>
|
||||
<Home id=""1172"" parentID=""-1"" level=""1"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""1045"" sortOrder=""3"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""Test"" urlName=""test"" writerName=""admin"" creatorName=""admin"" path=""-1,1172"" isDoc="""" />
|
||||
</root>";
|
||||
@@ -154,6 +156,7 @@ namespace Umbraco.Tests.ContentStores
|
||||
[TestCase("/home/sub1", 1173)]
|
||||
[TestCase("/Home/sub1", 1173)]
|
||||
[TestCase("/home/Sub1", 1173)] //test different cases
|
||||
[TestCase("/home/Sub'Apostrophe", 1177)]
|
||||
public void Get_Node_By_Route(string route, int nodeId)
|
||||
{
|
||||
var result = _publishedContentStore.GetDocumentByRoute(_umbracoContext, route, false);
|
||||
|
||||
@@ -29,7 +29,8 @@ namespace Umbraco.Web
|
||||
public string DescendantDocumentById { get; private set; }
|
||||
public string DescendantDocumentByAlias { get; private set; }
|
||||
public string ChildDocumentByUrlName { get; private set; }
|
||||
public string RootDocumentWithLowestSortOrder { get; private set; }
|
||||
public string ChildDocumentByUrlNameVar { get; private set; }
|
||||
public string RootDocumentWithLowestSortOrder { get; private set; }
|
||||
|
||||
public XPathStringsDefinition(int version)
|
||||
{
|
||||
@@ -46,6 +47,7 @@ namespace Umbraco.Web
|
||||
+ " or contains(concat(',',translate(data [@alias='umbracoUrlAlias'], ' ', ''),','),',/{0},')"
|
||||
+ ")]";
|
||||
ChildDocumentByUrlName = "/node [@urlName='{0}']";
|
||||
ChildDocumentByUrlNameVar = "/node [@urlName=${0}]";
|
||||
RootDocumentWithLowestSortOrder = "/root/node [not(@sortOrder > ../node/@sortOrder)][1]";
|
||||
break;
|
||||
|
||||
@@ -58,6 +60,7 @@ namespace Umbraco.Web
|
||||
+ " or contains(concat(',',translate(umbracoUrlAlias, ' ', ''),','),',/{0},')"
|
||||
+ ")]";
|
||||
ChildDocumentByUrlName = "/* [@isDoc and @urlName='{0}']";
|
||||
ChildDocumentByUrlNameVar = "/* [@isDoc and @urlName=${0}]";
|
||||
RootDocumentWithLowestSortOrder = "/root/* [@isDoc and not(@sortOrder > ../* [@isDoc]/@sortOrder)][1]";
|
||||
break;
|
||||
|
||||
@@ -248,12 +251,18 @@ namespace Umbraco.Web
|
||||
varsList = varsList ?? new List<XPathVariable>();
|
||||
var varName = string.Format("var{0}", partsIndex);
|
||||
varsList.Add(new XPathVariable(varName, part));
|
||||
part = "$" + varName;
|
||||
xpathBuilder.AppendFormat(XPathStrings.ChildDocumentByUrlNameVar, varName);
|
||||
}
|
||||
else
|
||||
{
|
||||
xpathBuilder.AppendFormat(XPathStrings.ChildDocumentByUrlName, part);
|
||||
|
||||
}
|
||||
xpathBuilder.AppendFormat(XPathStrings.ChildDocumentByUrlName, part);
|
||||
}
|
||||
|
||||
xpath = xpathBuilder.ToString();
|
||||
if (varsList != null)
|
||||
vars = varsList.ToArray();
|
||||
}
|
||||
|
||||
return xpath;
|
||||
|
||||
@@ -68,8 +68,13 @@ namespace Umbraco.Web.Routing
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Finder '{0}' found node with id={1}.", () => finder.GetType().FullName, () => docRequest.PublishedContent.Id);
|
||||
if (docRequest.Is404)
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Finder '{0}' set status to 404.", () => finder.GetType().FullName);
|
||||
|
||||
// if we found a document, break, don't look at more handler -- we're done
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
// if we did not find a document, continue, look at other handlers
|
||||
continue;
|
||||
}
|
||||
|
||||
// else it's a legacy handler, run
|
||||
@@ -108,8 +113,11 @@ namespace Umbraco.Web.Routing
|
||||
// string.Format("Added to cache '{0}', {1}.", url, handler.redirectID));
|
||||
//}
|
||||
|
||||
// if we found a document, break, don't look at more handler -- we're done
|
||||
break;
|
||||
}
|
||||
|
||||
// if we did not find a document, continue, look at other handlers
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user