diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/ListTokens.cs b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/ListTokens.cs index d8c9856ae..43b72c085 100644 --- a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/ListTokens.cs +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/ListTokens.cs @@ -23,85 +23,96 @@ namespace Orchard.Tokens.Providers { .Token("Sum:*", T("Sum:"), T("Sum each element in the list by applying the tokenized text.")) .Token("First:*", T("First:"), T("Apply the tokenized text to the first element.")) .Token("Last:*", T("Last:"), T("Apply the tokenized text to the last element.")) - .Token("Count", T("Count"), T("Get the list count.")) - ; + .Token("Count", T("Count"), T("Get the list count.")) + .Token("ElementAt:*", T("ElementAt:,"), T("Apply the tokenized text to the element at its index.")) + ; } public void Evaluate(EvaluateContext context) { - Func getValue = (t, i) => _tokenizer().Replace(t, new { Content = i }, new ReplaceOptions { Encoding = ReplaceOptions.NoEncode }); + Func tokenValue = (t, i) => _tokenizer().Replace(t, new { Content = i }, new ReplaceOptions { Encoding = ReplaceOptions.NoEncode }); context.For>("List", () => new List()) .Token( // {List.Join:[,]} - token => { - if (token.StartsWith("Join:", StringComparison.OrdinalIgnoreCase)) { - // html decode to stop double encoding. - return HttpUtility.HtmlDecode(token.Substring("Join:".Length)); - } - return null; - }, - (token, collection) => { - if (String.IsNullOrEmpty(token)) { + token => FilterToken(token, "Join:"), + (token, list) => { + if (String.IsNullOrEmpty(token) || !list.Any()) { return String.Empty; } - // Split the params to get the tokenized text and optional separator. + // Split the token to get the tokenized text and optional separator. var index = token.IndexOf(','); var text = index == -1 ? token : token.Substring(0, index); if (String.IsNullOrEmpty(text)) { return String.Empty; } var separator = index == -1 ? String.Empty : token.Substring(index + 1); - return String.Join(separator, collection.Select(content => getValue(text, content))); + return String.Join(separator, list.Select(content => tokenValue(text, content))); }) .Token( // {List.Sum:} - token => { - if (token.StartsWith("Sum:", StringComparison.OrdinalIgnoreCase)) { - // html decode to stop double encoding. - return HttpUtility.HtmlDecode(token.Substring("Sum:".Length)); - } - return null; - }, - (token, collection) => { - if (!collection.Any()) return "0"; + token => FilterToken(token, "Sum:"), + (token, list) => { + if (String.IsNullOrEmpty(token) || !list.Any()) { + return "0"; + } // try long. long longValue; - if (long.TryParse(collection.Select(i => getValue(token, i)).First(), out longValue)) { - return collection.Sum(i => long.Parse(getValue(token, i))); + if (long.TryParse(list.Select(i => tokenValue(token, i)).First(), out longValue)) { + return list.Sum(i => long.Parse(tokenValue(token, i))); } // try float. float floatValue; - if (float.TryParse(collection.Select(i => getValue(token, i)).First(), out floatValue)) { - return collection.Sum(i => float.Parse(getValue(token, i))); + if (float.TryParse(list.Select(i => tokenValue(token, i)).First(), out floatValue)) { + return list.Sum(i => float.Parse(tokenValue(token, i))); } // try decimal. decimal decimalValue; - if (decimal.TryParse(collection.Select(i => getValue(token, i)).First(), out decimalValue)) { - return collection.Sum(i => decimal.Parse(getValue(token, i))); + if (decimal.TryParse(list.Select(i => tokenValue(token, i)).First(), out decimalValue)) { + return list.Sum(i => decimal.Parse(tokenValue(token, i))); } return ""; }) .Token( // {List.First:} - token => { - if (token.StartsWith("First:", StringComparison.OrdinalIgnoreCase)) { - // html decode to stop double encoding. - return HttpUtility.HtmlDecode(token.Substring("First:".Length)); - } - return null; - }, - (token, list) => list.Any() ? list.Select(i => getValue(token, i)).First() : String.Empty) + token => FilterToken(token, "First:"), + (token, list) => String.IsNullOrEmpty(token) || !list.Any() ? String.Empty : list.Select(i => tokenValue(token, i)).First()) .Token( // {List.Last:} - token => { - if (token.StartsWith("Last:", StringComparison.OrdinalIgnoreCase)) { - // html decode to stop double encoding. - return HttpUtility.HtmlDecode(token.Substring("Last:".Length)); - } - return null; - }, - (token, list) => list.Any() ? list.Select(i => getValue(token, i)).Last() : String.Empty) + token => FilterToken(token, "Last:"), + (token, list) => String.IsNullOrEmpty(token) || !list.Any() ? String.Empty : list.Select(i => tokenValue(token, i)).Last()) .Token( // {List.Count} "Count", list => list.Count) - ; + .Token( // {List.ElementAt:,} + token => FilterToken(token, "ElementAt:"), + (token, list) => { + if (String.IsNullOrEmpty(token) || !list.Any()) { + return String.Empty; + } + // Split the token to get the index and the tokenized text. + var delimiterIndex = token.IndexOf(','); + if (delimiterIndex == -1) { + return String.Empty; + } + + var text = token.Substring(delimiterIndex + 1); + if (String.IsNullOrEmpty(text)) { + return String.Empty; + } + + var index= 0; + if (!int.TryParse(token.Substring(0, delimiterIndex), out index)) { + return String.Empty; + } + + return list.Select(i => tokenValue(text, i)).ElementAt(index); + }) + ; } + + private static string FilterToken(string token, string operation) { + if (token.StartsWith(operation, StringComparison.OrdinalIgnoreCase)) { + // html decode to stop double encoding. + return HttpUtility.HtmlDecode(token.Substring(operation.Length)); + } + return null; + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Tests/ListTokenTests.cs b/src/Orchard.Web/Modules/Orchard.Tokens/Tests/ListTokenTests.cs index b870dd68e..99bb895d1 100644 --- a/src/Orchard.Web/Modules/Orchard.Tokens/Tests/ListTokenTests.cs +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Tests/ListTokenTests.cs @@ -51,9 +51,14 @@ namespace Orchard.Tokens.Tests { [Test] public void TestListCountTokens() { Assert.That(_tokenizer.Replace("{List.Count}", new {List = new List {new TestUser(), new TestUser()}}), Is.EqualTo("2")); - } + } - [Test] + [Test] + public void TestListElementAtTokens() { + Assert.That(_tokenizer.Replace("{List.ElementAt:1,UserId is: {Content.Id}}", new { List = new List { new TestUser { Id = 5 }, new TestUser { Id = 10 } } }), Is.EqualTo("UserId is: 10")); + } + + [Test] public void TestListTokensAdhereToEncodings() { Assert.That(_tokenizer.Replace( "{List.Join:{Content.Id}}",