Fixes: #U4-1822, #U4-1797 - Is helpers and indexes on result collections using IPublishedContent or DynamicPublishedContent were incorrect,

added unit tests to support issues and fixes.
This commit is contained in:
Shannon Deminick
2013-03-02 01:02:38 +06:00
parent a17a11d50b
commit 010893a73a
16 changed files with 736 additions and 277 deletions

View File

@@ -716,7 +716,8 @@ namespace Umbraco.Core.Dynamics
}
public IEnumerable<DynamicXml> Descendants(Func<XElement, bool> func)
{
var flattenedNodes = this.BaseElement.Elements().Map(func, n => n.Elements());
//var flattenedNodes = this.BaseElement.Elements().Map(func, n => n.Elements());
var flattenedNodes = this.BaseElement.Elements().SelectMany(n => n.Elements()).Where(func);
return flattenedNodes.ToList().ConvertAll(n => new DynamicXml(n));
}
public IEnumerable<DynamicXml> DescendantsOrSelf()
@@ -725,7 +726,8 @@ namespace Umbraco.Core.Dynamics
}
public IEnumerable<DynamicXml> DescendantsOrSelf(Func<XElement, bool> func)
{
var flattenedNodes = this.BaseElement.Elements().Map(func, n => n.Elements());
//var flattenedNodes = this.BaseElement.Elements().Map(func, n => n.Elements());
var flattenedNodes = this.BaseElement.Elements().SelectMany(n => n.Elements()).Where(func);
var list = new List<DynamicXml>();
list.Add(this);
list.AddRange(flattenedNodes.ToList().ConvertAll(n => new DynamicXml(n)));

View File

@@ -5,36 +5,35 @@ using Umbraco.Core.Models;
namespace Umbraco.Core.Dynamics
{
[Obsolete("This class should not be used, it is just referenced by already obsoleted code and will be removed in the future")]
internal static class ExtensionMethods
{
public static IEnumerable<TSource> Map<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> selectorFunction,
Func<TSource, IEnumerable<TSource>> getChildrenFunction)
{
if (!source.Any())
{
return source;
}
// Add what we have to the stack
var flattenedList = source.Where(selectorFunction);
// Go through the input enumerable looking for children,
// and add those if we have them
foreach (TSource element in source)
{
var secondInner = getChildrenFunction(element);
if (secondInner.Any())
{
secondInner = secondInner.Map(selectorFunction, getChildrenFunction);
}
flattenedList = flattenedList.Concat(secondInner);
}
return flattenedList;
}
//public static IEnumerable<TSource> Map<TSource>(
// this IEnumerable<TSource> source,
// Func<TSource, bool> selectorFunction,
// Func<TSource, IEnumerable<TSource>> getChildrenFunction)
//{
// if (!source.Any())
// {
// return source;
// }
// // Add what we have to the stack
// var flattenedList = source.Where(selectorFunction);
// // Go through the input enumerable looking for children,
// // and add those if we have them
// foreach (TSource element in source)
// {
// var secondInner = getChildrenFunction(element);
// if (secondInner.Any())
// {
// secondInner = secondInner.Map(selectorFunction, getChildrenFunction);
// }
// flattenedList = flattenedList.Concat(secondInner);
// }
// return flattenedList;
//}
[Obsolete("This method should not be used and will be removed in the future")]
public static bool ContainsAny(this string haystack, IEnumerable<string> needles)
{
if (haystack == null) throw new ArgumentNullException("haystack");
@@ -44,6 +43,7 @@ namespace Umbraco.Core.Dynamics
}
return false;
}
[Obsolete("This method should not be used and will be removed in the future")]
public static bool ContainsAny(this string haystack, params string[] needles)
{
if (haystack == null) throw new ArgumentNullException("haystack");
@@ -53,6 +53,7 @@ namespace Umbraco.Core.Dynamics
}
return false;
}
[Obsolete("This method should not be used and will be removed in the future")]
public static bool ContainsAny(this string haystack, StringComparison comparison, IEnumerable<string> needles)
{
if (haystack == null) throw new ArgumentNullException("haystack");
@@ -62,6 +63,7 @@ namespace Umbraco.Core.Dynamics
}
return false;
}
[Obsolete("This method should not be used and will be removed in the future")]
public static bool ContainsAny(this string haystack, StringComparison comparison, params string[] needles)
{
if (haystack == null) throw new ArgumentNullException("haystack");
@@ -71,12 +73,13 @@ namespace Umbraco.Core.Dynamics
}
return false;
}
[Obsolete("This method should not be used and will be removed in the future")]
public static bool ContainsInsensitive(this string haystack, string needle)
{
if (haystack == null) throw new ArgumentNullException("haystack");
return haystack.IndexOf(needle, StringComparison.CurrentCultureIgnoreCase) >= 0;
}
[Obsolete("This method should not be used and will be removed in the future")]
public static bool HasValue(this string s)
{
return !string.IsNullOrWhiteSpace(s);

View File

@@ -472,6 +472,12 @@ namespace Umbraco.Core.Models
return xml;
}
/// <summary>
/// Used by ToDeepXml to recursively add children
/// </summary>
/// <param name="originalDescendants"></param>
/// <param name="currentChildren"></param>
/// <param name="currentXml"></param>
private static void AddChildXml(
IContent[] originalDescendants,
IEnumerable<IContent> currentChildren,

View File

@@ -46,17 +46,18 @@ namespace Umbraco.Tests.PublishedContent
<Home id=""1173"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2012-07-20T18:06:45"" updateDate=""2012-07-20T19:07:31"" nodeName=""Sub1"" urlName=""sub1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173"" isDoc="""">
<content><![CDATA[<div>This is some content</div>]]></content>
<umbracoUrlAlias><![CDATA[page2/alias, 2ndpagealias]]></umbracoUrlAlias>
<Home id=""1174"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2012-07-20T18:07:54"" updateDate=""2012-07-20T19:10:27"" nodeName=""Sub2"" urlName=""sub2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1174"" isDoc="""">
<Home id=""1174"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""1"" createDate=""2012-07-20T18:07:54"" updateDate=""2012-07-20T19:10:27"" nodeName=""Sub2"" urlName=""sub2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1174"" isDoc="""">
<content><![CDATA[]]></content>
<umbracoUrlAlias><![CDATA[only/one/alias]]></umbracoUrlAlias>
<creatorName><![CDATA[Custom data with same property name as the member name]]></creatorName>
</Home>
<Home id=""1176"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""3"" createDate=""2012-07-20T18:08:08"" updateDate=""2012-07-20T19:10:52"" nodeName=""Sub 3"" urlName=""sub-3"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1176"" isDoc="""">
</Home>
<CustomDocument id=""1177"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""custom sub 1"" urlName=""custom-sub-1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1177"" isDoc="""" />
<CustomDocument id=""1178"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""3"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-16T14:23:35"" nodeName=""custom sub 2"" urlName=""custom-sub-2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1178"" isDoc="""" />
<Home id=""1176"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""4"" createDate=""2012-07-20T18:08:08"" updateDate=""2012-07-20T19:10:52"" nodeName=""Sub 3"" urlName=""sub-3"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1176"" isDoc="""">
<content><![CDATA[some content]]></content>
<blah><![CDATA[some content]]></blah>
<umbracoNaviHide>1</umbracoNaviHide>
</Home>
<CustomDocument id=""1177"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""4"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""custom sub 1"" urlName=""custom-sub-1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1177"" isDoc="""" />
<CustomDocument id=""1178"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""4"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-16T14:23:35"" nodeName=""custom sub 2"" urlName=""custom-sub-2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1178"" isDoc="""" />
</Home>
<Home id=""1175"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""3"" 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>
@@ -77,6 +78,28 @@ namespace Umbraco.Tests.PublishedContent
/// <returns></returns>
protected abstract dynamic GetDynamicNode(int id);
/// <summary>
/// Tests the IsLast method with the result set from a Where statement
/// </summary>
[Test]
public void Is_Last_From_Where_Filter()
{
var doc = GetDynamicNode(1173);
foreach (var d in doc.Children.Where("Visible"))
{
if (d.Id != 1178)
{
Assert.IsFalse(d.IsLast());
}
else
{
Assert.IsTrue(d.IsLast());
}
}
}
[Test]
public void Single()
{
@@ -222,11 +245,11 @@ namespace Umbraco.Tests.PublishedContent
var doc = GetDynamicNode(1173);
Assert.AreEqual(0, doc.Index());
doc = GetDynamicNode(1176);
Assert.AreEqual(1, doc.Index());
doc = GetDynamicNode(1177);
Assert.AreEqual(2, doc.Index());
doc = GetDynamicNode(1178);
Assert.AreEqual(3, doc.Index());
doc = GetDynamicNode(1177);
Assert.AreEqual(1, doc.Index());
doc = GetDynamicNode(1178);
Assert.AreEqual(2, doc.Index());
}
[Test]
@@ -372,7 +395,7 @@ namespace Umbraco.Tests.PublishedContent
var casted = (IEnumerable<TDocument>)skip;
Assert.AreEqual(2, casted.Count());
Assert.IsTrue(casted.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[]{1177, 1178}));
Assert.IsTrue(casted.Select(x => ((dynamic) x).Id).ContainsAll(new dynamic[] {1178, 1176}));
}
@@ -397,7 +420,7 @@ namespace Umbraco.Tests.PublishedContent
var casted = (IEnumerable<TDocument>)take;
Assert.AreEqual(2, casted.Count());
Assert.IsTrue(casted.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1174, 1176 }));
Assert.IsTrue(casted.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1174, 1177 }));
}
[Test]
@@ -615,7 +638,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Next_Without_Sibling()
{
var asDynamic = GetDynamicNode(1178);
var asDynamic = GetDynamicNode(1176);
Assert.IsNull(asDynamic.Next());
}
@@ -637,7 +660,7 @@ namespace Umbraco.Tests.PublishedContent
Assert.IsNotNull(result);
Assert.AreEqual((int) 1174, (int) result.Id);
Assert.AreEqual((int)1178, (int)result.Id);
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using NUnit.Framework;
@@ -36,25 +37,26 @@ namespace Umbraco.Tests.PublishedContent
<umbracoUrlAlias><![CDATA[this/is/my/alias, anotheralias]]></umbracoUrlAlias>
<umbracoNaviHide>1</umbracoNaviHide>
<testRecursive><![CDATA[This is the recursive val]]></testRecursive>
<Home id=""1173"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2012-07-20T18:06:45"" updateDate=""2012-07-20T19:07:31"" nodeName=""Sub1"" urlName=""sub1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173"" isDoc="""">
<Home id=""1173"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""1"" createDate=""2012-07-20T18:06:45"" updateDate=""2012-07-20T19:07:31"" nodeName=""Sub1"" urlName=""sub1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173"" isDoc="""">
<content><![CDATA[<div>This is some content</div>]]></content>
<umbracoUrlAlias><![CDATA[page2/alias, 2ndpagealias]]></umbracoUrlAlias>
<testRecursive><![CDATA[]]></testRecursive>
<Home id=""1174"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2012-07-20T18:07:54"" updateDate=""2012-07-20T19:10:27"" nodeName=""Sub2"" urlName=""sub2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1174"" isDoc="""">
<Home id=""1174"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""1"" createDate=""2012-07-20T18:07:54"" updateDate=""2012-07-20T19:10:27"" nodeName=""Sub2"" urlName=""sub2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1174"" isDoc="""">
<content><![CDATA[]]></content>
<umbracoUrlAlias><![CDATA[only/one/alias]]></umbracoUrlAlias>
<creatorName><![CDATA[Custom data with same property name as the member name]]></creatorName>
<testRecursive><![CDATA[]]></testRecursive>
</Home>
<Home id=""1176"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""3"" createDate=""2012-07-20T18:08:08"" updateDate=""2012-07-20T19:10:52"" nodeName=""Sub 3"" urlName=""sub-3"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1176"" isDoc="""">
</Home>
<CustomDocument id=""1177"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""custom sub 1"" urlName=""custom-sub-1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1177"" isDoc="""" />
<CustomDocument id=""1178"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""3"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-16T14:23:35"" nodeName=""custom sub 2"" urlName=""custom-sub-2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1178"" isDoc="""" />
<Home id=""1176"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""4"" createDate=""2012-07-20T18:08:08"" updateDate=""2012-07-20T19:10:52"" nodeName=""Sub 3"" urlName=""sub-3"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1176"" isDoc="""">
<content><![CDATA[]]></content>
<umbracoNaviHide>1</umbracoNaviHide>
</Home>
<CustomDocument id=""1177"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""4"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""custom sub 1"" urlName=""custom-sub-1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1177"" isDoc="""" />
<CustomDocument id=""1178"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""4"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-16T14:23:35"" nodeName=""custom sub 2"" urlName=""custom-sub-2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1178"" isDoc="""" />
</Home>
<Home id=""1175"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""3"" 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 id=""1175"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" 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>
<CustomDocument id=""4444"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""4"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""Test"" urlName=""test-page"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,4444"" isDoc="""">
<CustomDocument id=""4444"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""3"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""Test"" urlName=""test-page"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,4444"" isDoc="""">
<selectedNodes><![CDATA[1172,1176,1173]]></selectedNodes>
</CustomDocument>
</Home>
@@ -85,7 +87,123 @@ namespace Umbraco.Tests.PublishedContent
return doc;
}
[Test]
[Test]
public void Is_Last_From_Where_Filter_Dynamic_Linq()
{
var doc = GetNode(1173);
foreach (var d in doc.Children.Where("Visible"))
{
if (d.Id != 1178)
{
Assert.IsFalse(d.IsLast());
}
else
{
Assert.IsTrue(d.IsLast());
}
}
}
[Test]
public void Is_Last_From_Where_Filter()
{
var doc = GetNode(1173);
foreach (var d in doc.Children.Where(x => x.IsVisible()))
{
if (d.Id != 1178)
{
Assert.IsFalse(d.IsLast());
}
else
{
Assert.IsTrue(d.IsLast());
}
}
}
[Test]
public void Is_Last_From_Take()
{
var doc = GetNode(1173);
foreach (var d in doc.Children.Take(3))
{
if (d.Id != 1178)
{
Assert.IsFalse(d.IsLast());
}
else
{
Assert.IsTrue(d.IsLast());
}
}
}
[Test]
public void Is_Last_From_Skip()
{
var doc = GetNode(1173);
foreach (var d in doc.Children.Skip(1))
{
if (d.Id != 1176)
{
Assert.IsFalse(d.IsLast());
}
else
{
Assert.IsTrue(d.IsLast());
}
}
}
[Test]
public void Is_Last_From_Concat()
{
var doc = GetNode(1173);
foreach (var d in doc.Children.Concat(new[] { GetNode(1175), GetNode(4444) }))
{
if (d.Id != 4444)
{
Assert.IsFalse(d.IsLast());
}
else
{
Assert.IsTrue(d.IsLast());
}
}
}
[Test]
public void Descendants_Ordered_Properly()
{
var doc = GetNode(1046);
var currentLevel = 0;
var lastSortOrder = 0;
var levelChangesAt = new[] { 1046, 1173, 1174 };
foreach (var d in doc.DescendantsOrSelf())
{
if (levelChangesAt.Contains(d.Id))
{
Assert.Greater(d.Level, currentLevel);
currentLevel = d.Level;
}
else
{
Assert.AreEqual(currentLevel, d.Level);
Assert.Greater(d.SortOrder, lastSortOrder);
}
lastSortOrder = d.SortOrder;
}
}
[Test]
public void Test_Get_Recursive_Val()
{
var doc = GetNode(1174);
@@ -128,11 +246,11 @@ namespace Umbraco.Tests.PublishedContent
var doc = GetNode(1173);
Assert.AreEqual(0, doc.Index());
doc = GetNode(1176);
Assert.AreEqual(1, doc.Index());
doc = GetNode(1177);
Assert.AreEqual(2, doc.Index());
doc = GetNode(1178);
Assert.AreEqual(3, doc.Index());
doc = GetNode(1177);
Assert.AreEqual(1, doc.Index());
doc = GetNode(1178);
Assert.AreEqual(2, doc.Index());
}
[Test]
@@ -363,7 +481,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Next_Without_Sibling()
{
var doc = GetNode(1178);
var doc = GetNode(1176);
Assert.IsNull(doc.Next());
}
@@ -385,7 +503,7 @@ namespace Umbraco.Tests.PublishedContent
Assert.IsNotNull(result);
Assert.AreEqual((int)1174, (int)result.Id);
Assert.AreEqual((int)1178, (int)result.Id);
}
}
}

View File

@@ -7,6 +7,7 @@ using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
using Umbraco.Tests.TestHelpers;
using Umbraco.Web;
using Umbraco.Web.Models;
namespace Umbraco.Tests.PublishedContent
{
@@ -214,7 +215,7 @@ namespace Umbraco.Tests.PublishedContent
}
}
public class PublishedContentWrapper : IPublishedContent
public class PublishedContentWrapper : IPublishedContent, IOwnerCollectionAware<IPublishedContent>
{
protected IPublishedContent WrappedContent { get; private set; }
@@ -320,6 +321,46 @@ namespace Umbraco.Tests.PublishedContent
{
return WrappedContent.GetProperty(alias);
}
private IEnumerable<IPublishedContent> _ownersCollection;
/// <summary>
/// Need to get/set the owner collection when an item is returned from the result set of a query
/// </summary>
/// <remarks>
/// Based on this issue here: http://issues.umbraco.org/issue/U4-1797
/// </remarks>
IEnumerable<IPublishedContent> IOwnerCollectionAware<IPublishedContent>.OwnersCollection
{
get
{
var publishedContentBase = WrappedContent as IOwnerCollectionAware<IPublishedContent>;
if (publishedContentBase != null)
{
return publishedContentBase.OwnersCollection;
}
//if the owners collection is null, we'll default to it's siblings
if (_ownersCollection == null)
{
//get the root docs if parent is null
_ownersCollection = this.Siblings();
}
return _ownersCollection;
}
set
{
var publishedContentBase = WrappedContent as IOwnerCollectionAware<IPublishedContent>;
if (publishedContentBase != null)
{
publishedContentBase.OwnersCollection = value;
}
else
{
_ownersCollection = value;
}
}
}
}
public partial class HomeContentItem : ContentPageContentItem

View File

@@ -11,7 +11,7 @@ namespace Umbraco.Web.Dynamics
internal class Grouping<K, T> : IGrouping<K, T> where T : DynamicObject
{
public K Key { get; set; }
public IEnumerable<T> Elements;
public IEnumerable<T> Elements { get; set; }
public IEnumerator<T> GetEnumerator()
{

View File

@@ -20,9 +20,9 @@ namespace Umbraco.Web.Models
/// <summary>
/// The base dynamic model for views
/// </summary>
public class DynamicPublishedContent : DynamicObject, IPublishedContent
public class DynamicPublishedContent : DynamicObject, IPublishedContent, IOwnerCollectionAware<IPublishedContent>
{
protected IPublishedContent PublishedContent { get; private set; }
protected internal IPublishedContent PublishedContent { get; private set; }
private DynamicPublishedContentList _cachedChildren;
private readonly ConcurrentDictionary<string, object> _cachedMemberOutput = new ConcurrentDictionary<string, object>();
@@ -36,6 +36,46 @@ namespace Umbraco.Web.Models
#endregion
private IEnumerable<IPublishedContent> _ownersCollection;
/// <summary>
/// Need to get/set the owner collection when an item is returned from the result set of a query
/// </summary>
/// <remarks>
/// Based on this issue here: http://issues.umbraco.org/issue/U4-1797
/// </remarks>
IEnumerable<IPublishedContent> IOwnerCollectionAware<IPublishedContent>.OwnersCollection
{
get
{
var publishedContentBase = PublishedContent as IOwnerCollectionAware<IPublishedContent>;
if (publishedContentBase != null)
{
return publishedContentBase.OwnersCollection;
}
//if the owners collection is null, we'll default to it's siblings
if (_ownersCollection == null)
{
//get the root docs if parent is null
_ownersCollection = this.Siblings();
}
return _ownersCollection;
}
set
{
var publishedContentBase = PublishedContent as IOwnerCollectionAware<IPublishedContent>;
if (publishedContentBase != null)
{
publishedContentBase.OwnersCollection = value;
}
else
{
_ownersCollection = value;
}
}
}
public dynamic AsDynamic()
{
return this;

View File

@@ -11,10 +11,19 @@ using Umbraco.Web.Dynamics;
namespace Umbraco.Web.Models
{
public class DynamicPublishedContentList : DynamicObject, IEnumerable<DynamicPublishedContent>
/// <summary>
/// A collection of DynamicPublishedContent items
/// </summary>
/// <remarks>
/// Implements many of the dynamic methods required for execution against this list. It also ensures
/// that the correct OwnersCollection properties is assigned to the underlying PublishedContentBase object
/// of the DynamicPublishedContent item (so long as the IPublishedContent item is actually PublishedContentBase).
/// All relates to this issue here: http://issues.umbraco.org/issue/U4-1797
/// </remarks>
public class DynamicPublishedContentList : DynamicObject, IEnumerable<DynamicPublishedContent>, IEnumerable<IPublishedContent>
{
internal List<DynamicPublishedContent> Items { get; set; }
public DynamicPublishedContentList()
{
Items = new List<DynamicPublishedContent>();
@@ -22,14 +31,28 @@ namespace Umbraco.Web.Models
public DynamicPublishedContentList(IEnumerable<DynamicPublishedContent> items)
{
var list = items.ToList();
//set the owners list for each item
list.ForEach(x => SetOwnersList(x, this));
Items = list;
}
public DynamicPublishedContentList(IEnumerable<IPublishedContent> items)
{
var list = items.Select(x => new DynamicPublishedContent(x)).ToList();
//set the owners list for each item
list.ForEach(x => SetOwnersList(x, this));
Items = list;
}
private static void SetOwnersList(IPublishedContent content, IEnumerable<DynamicPublishedContent> list)
{
var publishedContentBase = content as IOwnerCollectionAware<IPublishedContent>;
if (publishedContentBase != null)
{
publishedContentBase.OwnersCollection = list;
}
}
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
{
int index = (int)indexes[0];
@@ -134,12 +157,12 @@ namespace Umbraco.Web.Models
}
if (name == "Take")
{
result = new DynamicPublishedContentList(this.Take((int)firstArg));
result = new DynamicPublishedContentList(this.Take<DynamicPublishedContent>((int)firstArg));
return true;
}
if (name == "Skip")
{
result = new DynamicPublishedContentList(this.Skip((int)firstArg));
result = new DynamicPublishedContentList(this.Skip<DynamicPublishedContent>((int)firstArg));
return true;
}
if (name == "InGroupsOf")
@@ -483,14 +506,26 @@ namespace Umbraco.Web.Models
return DynamicQueryable.Select(Items.AsQueryable(), predicate, values);
}
/// <summary>
/// Allows the adding of an item from the collection
/// </summary>
/// <param name="publishedContent"></param>
public void Add(DynamicPublishedContent publishedContent)
{
SetOwnersList(publishedContent, this);
this.Items.Add(publishedContent);
}
/// <summary>
/// Allows the removal of an item from the collection
/// </summary>
/// <param name="publishedContent"></param>
public void Remove(DynamicPublishedContent publishedContent)
{
if (this.Items.Contains(publishedContent))
{
//set owners list to null
SetOwnersList(publishedContent, null);
this.Items.Remove(publishedContent);
}
}
@@ -503,7 +538,12 @@ namespace Umbraco.Web.Models
return true;
}
public IEnumerator<DynamicPublishedContent> GetEnumerator()
IEnumerator<IPublishedContent> IEnumerable<IPublishedContent>.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<DynamicPublishedContent> GetEnumerator()
{
return Items.GetEnumerator();
}

View File

@@ -0,0 +1,12 @@
using System.Collections.Generic;
namespace Umbraco.Web.Models
{
/// <summary>
/// An interface describing that the object should be aware of it's containing collection
/// </summary>
internal interface IOwnerCollectionAware<T>
{
IEnumerable<T> OwnersCollection { get; set; }
}
}

View File

@@ -9,17 +9,42 @@ using Umbraco.Web.Templates;
namespace Umbraco.Web.Models
{
/// <summary>
/// <summary>
/// An abstract base class to use for IPublishedContent which ensures that the Url and Indexed property return values
/// are consistently returned.
/// </summary>
public abstract class PublishedContentBase : IPublishedContent
/// <remarks>
/// This also ensures that we have an OwnersCollection property so that the IsFirst/IsLast/Index helper methods work
/// when referenced inside the result of a collection. http://issues.umbraco.org/issue/U4-1797
/// </remarks>
public abstract class PublishedContentBase : IPublishedContent, IOwnerCollectionAware<IPublishedContent>
{
private string _url;
private readonly Dictionary<string, object> _resolvePropertyValues = new Dictionary<string, object>();
private IEnumerable<IPublishedContent> _ownersCollection;
/// <summary>
/// <summary>
/// Need to get/set the owner collection when an item is returned from the result set of a query
/// </summary>
/// <remarks>
/// Based on this issue here: http://issues.umbraco.org/issue/U4-1797
/// </remarks>
IEnumerable<IPublishedContent> IOwnerCollectionAware<IPublishedContent>.OwnersCollection
{
get
{
//if the owners collection is null, we'll default to it's siblings
if (_ownersCollection == null)
{
//get the root docs if parent is null
_ownersCollection = this.Siblings();
}
return _ownersCollection;
}
set { _ownersCollection = value; }
}
/// <summary>
/// Returns the Url for this content item
/// </summary>
/// <remarks>
@@ -98,5 +123,6 @@ namespace Umbraco.Web.Models
public abstract IPublishedContentProperty GetProperty(string alias);
public abstract IPublishedContent Parent { get; }
public abstract IEnumerable<IPublishedContent> Children { get; }
}
}
}

View File

@@ -72,7 +72,7 @@ namespace Umbraco.Web.Models
{
if (!_initialized)
Initialize();
return _children;
return _children.OrderBy(x => x.SortOrder);
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
@@ -272,9 +273,138 @@ namespace Umbraco.Web
}
#endregion
#region List Extensions
#region Linq Wrapping Extensions
public static IQueryable<IPublishedContent> OrderBy(this IEnumerable<IPublishedContent> list, string predicate)
//NOTE: These are all purely required to fix this issue: http://issues.umbraco.org/issue/U4-1797 which requires that any
// content item knows about it's containing collection.
public static IEnumerable<IPublishedContent> Where(this IEnumerable<IPublishedContent> source, Func<IPublishedContent, bool> predicate)
{
var internalResult = Enumerable.Where(source, predicate);
return new DynamicPublishedContentList(internalResult);
}
public static IEnumerable<IPublishedContent> Where(this IEnumerable<IPublishedContent> source, Func<IPublishedContent, int, bool> predicate)
{
var internalResult = Enumerable.Where(source, predicate);
return new DynamicPublishedContentList(internalResult);
}
public static IEnumerable<IPublishedContent> Take(this IEnumerable<IPublishedContent> source, int count)
{
var internalResult = Enumerable.Take(source, count);
return new DynamicPublishedContentList(internalResult);
}
public static IEnumerable<IPublishedContent> TakeWhile(this IEnumerable<IPublishedContent> source, Func<IPublishedContent, bool> predicate)
{
var internalResult = Enumerable.TakeWhile(source, predicate);
return new DynamicPublishedContentList(internalResult);
}
public static IEnumerable<IPublishedContent> TakeWhile(this IEnumerable<IPublishedContent> source, Func<IPublishedContent, int, bool> predicate)
{
var internalResult = Enumerable.TakeWhile(source, predicate);
return new DynamicPublishedContentList(internalResult);
}
public static IEnumerable<IPublishedContent> Skip(this IEnumerable<IPublishedContent> source, int count)
{
var internalResult = Enumerable.Skip(source, count);
return new DynamicPublishedContentList(internalResult);
}
public static IEnumerable<IPublishedContent> SkipWhile(this IEnumerable<IPublishedContent> source, Func<IPublishedContent, bool> predicate)
{
var internalResult = Enumerable.SkipWhile(source, predicate);
return new DynamicPublishedContentList(internalResult);
}
public static IEnumerable<IPublishedContent> SkipWhile(this IEnumerable<IPublishedContent> source, Func<IPublishedContent, int, bool> predicate)
{
var internalResult = Enumerable.SkipWhile(source, predicate);
return new DynamicPublishedContentList(internalResult);
}
public static IEnumerable<IPublishedContent> Concat(this IEnumerable<IPublishedContent> first, IEnumerable<IPublishedContent> second)
{
var internalResult = Enumerable.Concat(first, second);
return new DynamicPublishedContentList(internalResult);
}
public static IEnumerable<IPublishedContent> Distinct(this IEnumerable<IPublishedContent> source)
{
var internalResult = Enumerable.Distinct(source);
return new DynamicPublishedContentList(internalResult);
}
public static IEnumerable<IPublishedContent> Distinct(this IEnumerable<IPublishedContent> source, IEqualityComparer<IPublishedContent> comparer)
{
var internalResult = Enumerable.Distinct(source, comparer);
return new DynamicPublishedContentList(internalResult);
}
public static IEnumerable<IPublishedContent> Union(this IEnumerable<IPublishedContent> first, IEnumerable<IPublishedContent> second)
{
var internalResult = Enumerable.Union(first, second);
return new DynamicPublishedContentList(internalResult);
}
public static IEnumerable<IPublishedContent> Union(this IEnumerable<IPublishedContent> first, IEnumerable<IPublishedContent> second, IEqualityComparer<IPublishedContent> comparer)
{
var internalResult = Enumerable.Union(first, second, comparer);
return new DynamicPublishedContentList(internalResult);
}
public static IEnumerable<IPublishedContent> Intersect(this IEnumerable<IPublishedContent> first, IEnumerable<IPublishedContent> second)
{
var internalResult = Enumerable.Intersect(first, second);
return new DynamicPublishedContentList(internalResult);
}
public static IEnumerable<IPublishedContent> Intersect(this IEnumerable<IPublishedContent> first, IEnumerable<IPublishedContent> second, IEqualityComparer<IPublishedContent> comparer)
{
var internalResult = Enumerable.Intersect(first, second, comparer);
return new DynamicPublishedContentList(internalResult);
}
public static IEnumerable<IPublishedContent> Except(this IEnumerable<IPublishedContent> first, IEnumerable<IPublishedContent> second)
{
var internalResult = Enumerable.Except(first, second);
return new DynamicPublishedContentList(internalResult);
}
public static IEnumerable<IPublishedContent> Except(this IEnumerable<IPublishedContent> first, IEnumerable<IPublishedContent> second, IEqualityComparer<IPublishedContent> comparer)
{
var internalResult = Enumerable.Except(first, second, comparer);
return new DynamicPublishedContentList(internalResult);
}
public static IEnumerable<IPublishedContent> Reverse(this IEnumerable<IPublishedContent> source)
{
var internalResult = Enumerable.Reverse(source);
return new DynamicPublishedContentList(internalResult);
}
public static IEnumerable<IPublishedContent> DefaultIfEmpty(this IEnumerable<IPublishedContent> source)
{
var internalResult = Enumerable.DefaultIfEmpty(source);
return new DynamicPublishedContentList(internalResult);
}
public static IEnumerable<IPublishedContent> DefaultIfEmpty(this IEnumerable<IPublishedContent> source, IPublishedContent defaultValue)
{
var internalResult = Enumerable.DefaultIfEmpty(source, defaultValue);
return new DynamicPublishedContentList(internalResult);
}
#endregion
#region Dynamic Linq Extensions
public static IQueryable<IPublishedContent> OrderBy(this IEnumerable<IPublishedContent> list, string predicate)
{
var dList = new DynamicPublishedContentList(list);
return dList.OrderBy<DynamicPublishedContent>(predicate);
@@ -283,7 +413,11 @@ namespace Umbraco.Web
public static IQueryable<IPublishedContent> Where(this IEnumerable<IPublishedContent> list, string predicate)
{
var dList = new DynamicPublishedContentList(list);
return dList.Where<DynamicPublishedContent>(predicate);
//we have to wrap the result in another DynamicPublishedContentList so that the OwnersList get's set on
//the individual items. See: http://issues.umbraco.org/issue/U4-1797
return new DynamicPublishedContentList(
dList.Where<DynamicPublishedContent>(predicate))
.AsQueryable<IPublishedContent>();
}
public static IEnumerable<IGrouping<object, IPublishedContent>> GroupBy(this IEnumerable<IPublishedContent> list, string predicate)
@@ -336,14 +470,14 @@ namespace Umbraco.Web
}
return new HtmlString(valueIfFalse);
}
public static bool Where(this IPublishedContent doc, string predicate)
public static bool Where(this IPublishedContent doc, string predicate)
{
if (doc == null) throw new ArgumentNullException("doc");
//Totally gonna cheat here
var dynamicDocumentList = new DynamicPublishedContentList();
dynamicDocumentList.Add(doc.AsDynamicPublishedContent());
var filtered = dynamicDocumentList.Where<DynamicPublishedContent>(predicate);
if (Queryable.Count(filtered) == 1)
if (filtered.Count() == 1)
{
//this node matches the predicate
return true;
@@ -359,13 +493,8 @@ namespace Umbraco.Web
return content.Index();
}
public static int Index(this IPublishedContent content)
{
//get the root docs if parent is null
var ownersList = content.Parent == null
? PublishedContentStoreResolver.Current.PublishedContentStore.GetRootDocuments(UmbracoContext.Current)
: content.Parent.Children;
var container = ownersList.ToList();
{
var container = content.GetOwnersList().ToList();
int currentIndex = container.FindIndex(n => n.Id == content.Id);
if (currentIndex != -1)
{
@@ -376,6 +505,30 @@ namespace Umbraco.Web
throw new IndexOutOfRangeException(string.Format("Node {0} belongs to a DynamicDocumentList but could not retrieve the index for it's position in the list", content.Id));
}
}
/// <summary>
/// Return the owners collection of the current content item.
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
/// <remarks>
/// If the content item is of type PublishedContentBase we will have a property called OwnersCollection which will
/// be the collection of a resultant set (i.e. from a where clause, a call to Children(), etc...) otherwise it will
/// be the item's siblings. All relates to this issue: http://issues.umbraco.org/issue/U4-1797
/// </remarks>
private static IEnumerable<IPublishedContent> GetOwnersList(this IPublishedContent content)
{
//Here we need to type check, we need to see if we have a real OwnersCollection list based on the result set
// of a query, otherwise we can only lookup among the item's siblings. All related to this issue here:
// http://issues.umbraco.org/issue/U4-1797
var publishedContentBase = content as IOwnerCollectionAware<IPublishedContent>;
var ownersList = publishedContentBase != null
? publishedContentBase.OwnersCollection
: content.Siblings();
return ownersList;
}
#endregion
#region Is Helpers
@@ -394,159 +547,145 @@ namespace Umbraco.Web
public static bool IsNull(this IPublishedContent content, string alias)
{
return content.IsNull(alias, false);
}
public static bool IsFirst(this IPublishedContent content)
{
return content.IsHelper(n => n.Index() == 0);
}
public static HtmlString IsFirst(this IPublishedContent content, string valueIfTrue)
{
return content.IsHelper(n => n.Index() == 0, valueIfTrue);
}
public static HtmlString IsFirst(this IPublishedContent content, string valueIfTrue, string valueIfFalse)
{
return content.IsHelper(n => n.Index() == 0, valueIfTrue, valueIfFalse);
}
public static bool IsNotFirst(this IPublishedContent content)
{
return !content.IsHelper(n => n.Index() == 0);
}
public static HtmlString IsNotFirst(this IPublishedContent content, string valueIfTrue)
{
return content.IsHelper(n => n.Index() != 0, valueIfTrue);
}
public static HtmlString IsNotFirst(this IPublishedContent content, string valueIfTrue, string valueIfFalse)
{
return content.IsHelper(n => n.Index() != 0, valueIfTrue, valueIfFalse);
}
public static bool IsPosition(this IPublishedContent content, int index)
{
return content.IsHelper(n => n.Index() == index);
}
public static HtmlString IsPosition(this IPublishedContent content, int index, string valueIfTrue)
{
return content.IsHelper(n => n.Index() == index, valueIfTrue);
}
public static HtmlString IsPosition(this IPublishedContent content, int index, string valueIfTrue, string valueIfFalse)
{
return content.IsHelper(n => n.Index() == index, valueIfTrue, valueIfFalse);
}
public static bool IsModZero(this IPublishedContent content, int modulus)
{
return content.IsHelper(n => n.Index() % modulus == 0);
}
public static HtmlString IsModZero(this IPublishedContent content, int modulus, string valueIfTrue)
{
return content.IsHelper(n => n.Index() % modulus == 0, valueIfTrue);
}
public static HtmlString IsModZero(this IPublishedContent content, int modulus, string valueIfTrue, string valueIfFalse)
{
return content.IsHelper(n => n.Index() % modulus == 0, valueIfTrue, valueIfFalse);
}
}
public static bool IsNotModZero(this IPublishedContent content, int modulus)
{
return content.IsHelper(n => n.Index() % modulus != 0);
}
public static HtmlString IsNotModZero(this IPublishedContent content, int modulus, string valueIfTrue)
{
return content.IsHelper(n => n.Index() % modulus != 0, valueIfTrue);
}
public static HtmlString IsNotModZero(this IPublishedContent content, int modulus, string valueIfTrue, string valueIfFalse)
{
return content.IsHelper(n => n.Index() % modulus != 0, valueIfTrue, valueIfFalse);
}
public static bool IsNotPosition(this IPublishedContent content, int index)
{
return !content.IsHelper(n => n.Index() == index);
}
public static HtmlString IsNotPosition(this IPublishedContent content, int index, string valueIfTrue)
{
return content.IsHelper(n => n.Index() != index, valueIfTrue);
}
public static HtmlString IsNotPosition(this IPublishedContent content, int index, string valueIfTrue, string valueIfFalse)
{
return content.IsHelper(n => n.Index() != index, valueIfTrue, valueIfFalse);
}
public static bool IsLast(this IPublishedContent content)
{
//get the root docs if parent is null
var ownersList = content.Parent == null
? PublishedContentStoreResolver.Current.PublishedContentStore.GetRootDocuments(UmbracoContext.Current)
: content.Parent.Children;
var count = ownersList.Count();
return content.IsHelper(n => n.Index() == count - 1);
}
public static HtmlString IsLast(this IPublishedContent content, string valueIfTrue)
{
//get the root docs if parent is null
var ownersList = content.Parent == null
? PublishedContentStoreResolver.Current.PublishedContentStore.GetRootDocuments(UmbracoContext.Current)
: content.Parent.Children;
var count = ownersList.Count();
return content.IsHelper(n => n.Index() == count - 1, valueIfTrue);
}
public static HtmlString IsLast(this IPublishedContent content, string valueIfTrue, string valueIfFalse)
{
//get the root docs if parent is null
var ownersList = content.Parent == null
? PublishedContentStoreResolver.Current.PublishedContentStore.GetRootDocuments(UmbracoContext.Current)
: content.Parent.Children;
var count = ownersList.Count();
return content.IsHelper(n => n.Index() == count - 1, valueIfTrue, valueIfFalse);
}
public static bool IsNotLast(this IPublishedContent content)
{
//get the root docs if parent is null
var ownersList = content.Parent == null
? PublishedContentStoreResolver.Current.PublishedContentStore.GetRootDocuments(UmbracoContext.Current)
: content.Parent.Children;
var count = ownersList.Count();
return !content.IsHelper(n => n.Index() == count - 1);
}
public static HtmlString IsNotLast(this IPublishedContent content, string valueIfTrue)
{
//get the root docs if parent is null
var ownersList = content.Parent == null
? PublishedContentStoreResolver.Current.PublishedContentStore.GetRootDocuments(UmbracoContext.Current)
: content.Parent.Children;
var count = ownersList.Count();
return content.IsHelper(n => n.Index() != count - 1, valueIfTrue);
}
public static HtmlString IsNotLast(this IPublishedContent content, string valueIfTrue, string valueIfFalse)
{
//get the root docs if parent is null
var ownersList = content.Parent == null
? PublishedContentStoreResolver.Current.PublishedContentStore.GetRootDocuments(UmbracoContext.Current)
: content.Parent.Children;
var count = ownersList.Count();
return content.IsHelper(n => n.Index() != count - 1, valueIfTrue, valueIfFalse);
}
public static bool IsEven(this IPublishedContent content)
{
return content.IsHelper(n => n.Index() % 2 == 0);
}
public static HtmlString IsEven(this IPublishedContent content, string valueIfTrue)
{
return content.IsHelper(n => n.Index() % 2 == 0, valueIfTrue);
}
public static HtmlString IsEven(this IPublishedContent content, string valueIfTrue, string valueIfFalse)
{
return content.IsHelper(n => n.Index() % 2 == 0, valueIfTrue, valueIfFalse);
}
public static bool IsOdd(this IPublishedContent content)
{
return content.IsHelper(n => n.Index() % 2 == 1);
}
public static HtmlString IsOdd(this IPublishedContent content, string valueIfTrue)
{
return content.IsHelper(n => n.Index() % 2 == 1, valueIfTrue);
}
public static HtmlString IsOdd(this IPublishedContent content, string valueIfTrue, string valueIfFalse)
{
return content.IsHelper(n => n.Index() % 2 == 1, valueIfTrue, valueIfFalse);
}
public static bool IsEqual(this IPublishedContent content, IPublishedContent other)
#region Position in list
public static bool IsFirst(this IPublishedContent content)
{
return content.IsHelper(n => n.Index() == 0);
}
public static HtmlString IsFirst(this IPublishedContent content, string valueIfTrue)
{
return content.IsHelper(n => n.Index() == 0, valueIfTrue);
}
public static HtmlString IsFirst(this IPublishedContent content, string valueIfTrue, string valueIfFalse)
{
return content.IsHelper(n => n.Index() == 0, valueIfTrue, valueIfFalse);
}
public static bool IsNotFirst(this IPublishedContent content)
{
return !content.IsHelper(n => n.Index() == 0);
}
public static HtmlString IsNotFirst(this IPublishedContent content, string valueIfTrue)
{
return content.IsHelper(n => n.Index() != 0, valueIfTrue);
}
public static HtmlString IsNotFirst(this IPublishedContent content, string valueIfTrue, string valueIfFalse)
{
return content.IsHelper(n => n.Index() != 0, valueIfTrue, valueIfFalse);
}
public static bool IsPosition(this IPublishedContent content, int index)
{
return content.IsHelper(n => n.Index() == index);
}
public static HtmlString IsPosition(this IPublishedContent content, int index, string valueIfTrue)
{
return content.IsHelper(n => n.Index() == index, valueIfTrue);
}
public static HtmlString IsPosition(this IPublishedContent content, int index, string valueIfTrue, string valueIfFalse)
{
return content.IsHelper(n => n.Index() == index, valueIfTrue, valueIfFalse);
}
public static bool IsModZero(this IPublishedContent content, int modulus)
{
return content.IsHelper(n => n.Index() % modulus == 0);
}
public static HtmlString IsModZero(this IPublishedContent content, int modulus, string valueIfTrue)
{
return content.IsHelper(n => n.Index() % modulus == 0, valueIfTrue);
}
public static HtmlString IsModZero(this IPublishedContent content, int modulus, string valueIfTrue, string valueIfFalse)
{
return content.IsHelper(n => n.Index() % modulus == 0, valueIfTrue, valueIfFalse);
}
public static bool IsNotModZero(this IPublishedContent content, int modulus)
{
return content.IsHelper(n => n.Index() % modulus != 0);
}
public static HtmlString IsNotModZero(this IPublishedContent content, int modulus, string valueIfTrue)
{
return content.IsHelper(n => n.Index() % modulus != 0, valueIfTrue);
}
public static HtmlString IsNotModZero(this IPublishedContent content, int modulus, string valueIfTrue, string valueIfFalse)
{
return content.IsHelper(n => n.Index() % modulus != 0, valueIfTrue, valueIfFalse);
}
public static bool IsNotPosition(this IPublishedContent content, int index)
{
return !content.IsHelper(n => n.Index() == index);
}
public static HtmlString IsNotPosition(this IPublishedContent content, int index, string valueIfTrue)
{
return content.IsHelper(n => n.Index() != index, valueIfTrue);
}
public static HtmlString IsNotPosition(this IPublishedContent content, int index, string valueIfTrue, string valueIfFalse)
{
return content.IsHelper(n => n.Index() != index, valueIfTrue, valueIfFalse);
}
public static bool IsLast(this IPublishedContent content)
{
var ownersList = content.GetOwnersList();
var count = ownersList.Count();
return content.IsHelper(n => n.Index() == count - 1);
}
public static HtmlString IsLast(this IPublishedContent content, string valueIfTrue)
{
var ownersList = content.GetOwnersList();
var count = ownersList.Count();
return content.IsHelper(n => n.Index() == count - 1, valueIfTrue);
}
public static HtmlString IsLast(this IPublishedContent content, string valueIfTrue, string valueIfFalse)
{
var ownersList = content.GetOwnersList();
var count = ownersList.Count();
return content.IsHelper(n => n.Index() == count - 1, valueIfTrue, valueIfFalse);
}
public static bool IsNotLast(this IPublishedContent content)
{
var ownersList = content.GetOwnersList();
var count = ownersList.Count();
return !content.IsHelper(n => n.Index() == count - 1);
}
public static HtmlString IsNotLast(this IPublishedContent content, string valueIfTrue)
{
var ownersList = content.GetOwnersList();
var count = ownersList.Count();
return content.IsHelper(n => n.Index() != count - 1, valueIfTrue);
}
public static HtmlString IsNotLast(this IPublishedContent content, string valueIfTrue, string valueIfFalse)
{
var ownersList = content.GetOwnersList();
var count = ownersList.Count();
return content.IsHelper(n => n.Index() != count - 1, valueIfTrue, valueIfFalse);
}
public static bool IsEven(this IPublishedContent content)
{
return content.IsHelper(n => n.Index() % 2 == 0);
}
public static HtmlString IsEven(this IPublishedContent content, string valueIfTrue)
{
return content.IsHelper(n => n.Index() % 2 == 0, valueIfTrue);
}
public static HtmlString IsEven(this IPublishedContent content, string valueIfTrue, string valueIfFalse)
{
return content.IsHelper(n => n.Index() % 2 == 0, valueIfTrue, valueIfFalse);
}
public static bool IsOdd(this IPublishedContent content)
{
return content.IsHelper(n => n.Index() % 2 == 1);
}
public static HtmlString IsOdd(this IPublishedContent content, string valueIfTrue)
{
return content.IsHelper(n => n.Index() % 2 == 1, valueIfTrue);
}
public static HtmlString IsOdd(this IPublishedContent content, string valueIfTrue, string valueIfFalse)
{
return content.IsHelper(n => n.Index() % 2 == 1, valueIfTrue, valueIfFalse);
}
#endregion
public static bool IsEqual(this IPublishedContent content, IPublishedContent other)
{
return content.IsHelper(n => n.Id == other.Id);
}
@@ -782,7 +921,10 @@ namespace Umbraco.Web
}
private static IEnumerable<IPublishedContent> Descendants(this IPublishedContent content, Func<IPublishedContent, bool> func)
{
return content.Children.Map(func, (IPublishedContent n) => n.Children);
//return content.Children.Map(func, (IPublishedContent n) => n.Children);
return content.Children.FlattenList(x => x.Children).Where(func)
.OrderBy(x => x.Level) //ensure its sorted by level and then by sort order
.ThenBy(x => x.SortOrder);
}
public static IEnumerable<IPublishedContent> DescendantsOrSelf(this IPublishedContent content, int level)
{
@@ -805,8 +947,13 @@ namespace Umbraco.Web
{
thisNode.Add(content);
}
var flattenedNodes = content.Children.Map(func, (IPublishedContent n) => n.Children);
return thisNode.Concat(flattenedNodes).ToList().ConvertAll(dynamicBackingItem => new DynamicPublishedContent(dynamicBackingItem));
//var flattenedNodes = content.Children.Map(func, (IPublishedContent n) => n.Children);
var flattenedNodes = content.Children.FlattenList(n => n.Children).Where(func);
return thisNode.Concat(flattenedNodes)
.Select(dynamicBackingItem => new DynamicPublishedContent(dynamicBackingItem))
.OrderBy(x => x.Level) //ensure its sorted by level and then by sort order
.ThenBy(x => x.SortOrder);
}
return Enumerable.Empty<IPublishedContent>();
}
@@ -871,10 +1018,7 @@ namespace Umbraco.Web
}
public static IPublishedContent Next(this IPublishedContent content, int number)
{
//get the root docs if parent is null
var ownersList = content.Parent == null
? PublishedContentStoreResolver.Current.PublishedContentStore.GetRootDocuments(UmbracoContext.Current)
: content.Parent.Children;
var ownersList = content.GetOwnersList();
var container = ownersList.ToList();
var currentIndex = container.FindIndex(n => n.Id == content.Id);
@@ -887,10 +1031,7 @@ namespace Umbraco.Web
public static IPublishedContent Next(this IPublishedContent content, string nodeTypeAlias)
{
//get the root docs if parent is null
var ownersList = content.Parent == null
? PublishedContentStoreResolver.Current.PublishedContentStore.GetRootDocuments(UmbracoContext.Current)
: content.Parent.Children;
var ownersList = content.GetOwnersList();
var container = ownersList.ToList();
var currentIndex = container.FindIndex(n => n.Id == content.Id);
@@ -909,10 +1050,7 @@ namespace Umbraco.Web
}
public static IPublishedContent Previous(this IPublishedContent content, int number)
{
//get the root docs if parent is null
var ownersList = content.Parent == null
? PublishedContentStoreResolver.Current.PublishedContentStore.GetRootDocuments(UmbracoContext.Current)
: content.Parent.Children;
var ownersList = content.GetOwnersList();
var container = ownersList.ToList();
var currentIndex = container.FindIndex(n => n.Id == content.Id);
@@ -924,10 +1062,7 @@ namespace Umbraco.Web
}
public static IPublishedContent Previous(this IPublishedContent content, string nodeTypeAlias)
{
//get the root docs if parent is null
var ownersList = content.Parent == null
? PublishedContentStoreResolver.Current.PublishedContentStore.GetRootDocuments(UmbracoContext.Current)
: content.Parent.Children;
var ownersList = content.GetOwnersList();
var container = ownersList.ToList();
int currentIndex = container.FindIndex(n => n.Id == content.Id);
@@ -945,12 +1080,9 @@ namespace Umbraco.Web
}
public static IPublishedContent Sibling(this IPublishedContent content, int number)
{
//get the root docs if parent is null
var ownersList = content.Parent == null
? PublishedContentStoreResolver.Current.PublishedContentStore.GetRootDocuments(UmbracoContext.Current)
: content.Parent.Children;
var siblings = content.Siblings();
var container = ownersList.ToList();
var container = siblings.ToList();
var currentIndex = container.FindIndex(n => n.Id == content.Id);
if (currentIndex != -1)
{
@@ -959,13 +1091,10 @@ namespace Umbraco.Web
throw new IndexOutOfRangeException(string.Format("Node {0} belongs to a DynamicNodeList but could not retrieve the index for it's position in the list", content.Id));
}
public static IPublishedContent Sibling(this IPublishedContent content, string nodeTypeAlias)
{
//get the root docs if parent is null
var ownersList = content.Parent == null
? PublishedContentStoreResolver.Current.PublishedContentStore.GetRootDocuments(UmbracoContext.Current)
: content.Parent.Children;
{
var siblings = content.Siblings();
var container = ownersList.ToList();
var container = siblings.ToList();
var currentIndex = container.FindIndex(n => n.Id == content.Id);
if (currentIndex != -1)
{
@@ -987,7 +1116,21 @@ namespace Umbraco.Web
}
throw new IndexOutOfRangeException(string.Format("Node {0} belongs to a DynamicNodeList but could not retrieve the index for it's position in the list", content.Id));
}
#endregion
/// <summary>
/// Return the items siblings
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
public static IEnumerable<IPublishedContent> Siblings(this IPublishedContent content)
{
//get the root docs if parent is null
return content.Parent == null
? PublishedContentStoreResolver.Current.PublishedContentStore.GetRootDocuments(UmbracoContext.Current)
: content.Parent.Children;
}
#endregion
/// <summary>
/// Method to return the Children of the content item
@@ -999,7 +1142,7 @@ namespace Umbraco.Web
/// </remarks>
public static IEnumerable<IPublishedContent> Children(this IPublishedContent p)
{
return p.Children;
return p.Children.OrderBy(x => x.SortOrder);
}
/// <summary>
@@ -1043,7 +1186,7 @@ namespace Umbraco.Web
//create all row data
var tableData = Umbraco.Core.DataTableExtensions.CreateTableData();
//loop through each child and create row data for it
foreach (var n in node.Children)
foreach (var n in node.Children.OrderBy(x => x.SortOrder))
{
if (!nodeTypeAliasFilter.IsNullOrWhiteSpace())
{

View File

@@ -304,6 +304,7 @@
<Compile Include="Media\ImageUrlProviders\ImageUrlProvider.cs" />
<Compile Include="Models\DynamicPublishedContent.cs" />
<Compile Include="Models\DynamicPublishedContentList.cs" />
<Compile Include="Models\IOwnerCollectionAware.cs" />
<Compile Include="Models\PartialViewMacroModel.cs" />
<Compile Include="Models\PublishedContentBase.cs" />
<Compile Include="Mvc\AreaRegistrationExtensions.cs" />

View File

@@ -1025,8 +1025,9 @@ namespace umbraco.MacroEngines
}
public DynamicNodeList Descendants(Func<DynamicBackingItem, bool> func)
{
var flattenedNodes = this.n.ChildrenAsList.Map(func, (DynamicBackingItem n) => { return n.ChildrenAsList; });
return new DynamicNodeList(flattenedNodes.ToList().ConvertAll(DynamicBackingItem => new DynamicNode(DynamicBackingItem)));
//var flattenedNodes = this.n.ChildrenAsList.Map(func, (DynamicBackingItem n) => { return n.ChildrenAsList; });
var flattenedNodes = this.n.ChildrenAsList.FlattenList(item => item.ChildrenAsList).Where(func);
return new DynamicNodeList(flattenedNodes.Select(dynamicBackingItem => new DynamicNode(dynamicBackingItem)));
}
public DynamicNodeList DescendantsOrSelf(int level)
{
@@ -1049,8 +1050,9 @@ namespace umbraco.MacroEngines
{
thisNode.Add(this.n);
}
var flattenedNodes = this.n.ChildrenAsList.Map(func, (DynamicBackingItem n) => { return n.ChildrenAsList; });
return new DynamicNodeList(thisNode.Concat(flattenedNodes).ToList().ConvertAll(DynamicBackingItem => new DynamicNode(DynamicBackingItem)));
//var flattenedNodes = this.n.ChildrenAsList.Map(func, (DynamicBackingItem n) => { return n.ChildrenAsList; });
var flattenedNodes = this.n.ChildrenAsList.FlattenList(item => item.ChildrenAsList).Where(func);
return new DynamicNodeList(thisNode.Concat(flattenedNodes).Select(dynamicBackingItem => new DynamicNode(dynamicBackingItem)));
}
return new DynamicNodeList(new List<DynamicBackingItem>());
}

View File

@@ -3,18 +3,20 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using Umbraco.Core;
namespace umbraco.MacroEngines
{
public static class ExtensionMethods
{
[Obsolete("This has been superceded by Umbraco.Core.Dynamics.ExtensionMethods.Map method")]
[Obsolete("This has been superceded by Umbraco.Core.EnumerableExtensions.FlattenList method")]
public static IEnumerable<TSource> Map<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> selectorFunction,
Func<TSource, IEnumerable<TSource>> getChildrenFunction)
{
return Umbraco.Core.Dynamics.ExtensionMethods.Map<TSource>(source, selectorFunction, getChildrenFunction);
//return Umbraco.Core.Dynamics.ExtensionMethods.Map<TSource>(source, selectorFunction, getChildrenFunction);
return source.FlattenList(getChildrenFunction).Where(selectorFunction);
}
public static DynamicNodeList Random(this DynamicNodeList all, int Min, int Max)