diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs
index c771debbad..29a96f30b0 100644
--- a/src/Umbraco.Web/PublishedContentExtensions.cs
+++ b/src/Umbraco.Web/PublishedContentExtensions.cs
@@ -1,7 +1,3 @@
-// ENABLE THE FIX in 7.0.0
-// TODO if all goes well, remove the obsolete code eventually
-#define FIX_AXES
-
using System;
using System.Collections.Generic;
using System.Data;
@@ -911,148 +907,270 @@ namespace Umbraco.Web
// - the relative order of siblings is the order in which they occur in the children property of their parent node.
// - children and descendants occur before following siblings.
- // SO, here we want to walk up the tree. which is what AncestorOrSelf does but NOT what AncestorsOrSelf does since
- // it reverses the list, so basically ancestors are NOT XPath-compliant in Umbraco at the moment -- but fixing that
- // would be a breaking change. Defining FIX_AXES would fix the situation.
-
+ ///
+ /// Gets the ancestors of the content.
+ ///
+ /// The content.
+ /// The ancestors of the content, in down-top order.
+ /// Does not consider the content itself.
public static IEnumerable Ancestors(this IPublishedContent content)
{
return content.AncestorsOrSelf(false, null);
}
- public static IEnumerable Ancestors(this IPublishedContent content, int level)
+ ///
+ /// Gets the ancestors of the content, at a level lesser or equal to a specified level.
+ ///
+ /// The content.
+ /// The level.
+ /// The ancestors of the content, at a level lesser or equal to the specified level, in down-top order.
+ /// Does not consider the content itself. Only content that are "high enough" in the tree are returned.
+ public static IEnumerable Ancestors(this IPublishedContent content, int maxLevel)
{
- return content.AncestorsOrSelf(false, n => n.Level <= level);
+ return content.AncestorsOrSelf(false, n => n.Level <= maxLevel);
}
+ ///
+ /// Gets the ancestors of the content, of a specified content type.
+ ///
+ /// The content.
+ /// The content type.
+ /// The ancestors of the content, of the specified content type, in down-top order.
+ /// Does not consider the content itself. Returns all ancestors, of the specified content type.
public static IEnumerable Ancestors(this IPublishedContent content, string contentTypeAlias)
{
return content.AncestorsOrSelf(false, n => n.DocumentTypeAlias == contentTypeAlias);
}
+ ///
+ /// Gets the ancestors of the content, of a specified content type.
+ ///
+ /// The content type.
+ /// The content.
+ /// The ancestors of the content, of the specified content type, in down-top order.
+ /// Does not consider the content itself. Returns all ancestors, of the specified content type.
public static IEnumerable Ancestors(this IPublishedContent content)
where T : class, IPublishedContent
{
return content.Ancestors().OfType();
}
- public static IEnumerable Ancestors(this IPublishedContent content, int level)
+ ///
+ /// Gets the ancestors of the content, at a level lesser or equal to a specified level, and of a specified content type.
+ ///
+ /// The content type.
+ /// The content.
+ /// The level.
+ /// The ancestors of the content, at a level lesser or equal to the specified level, and of the specified
+ /// content type, in down-top order.
+ /// Does not consider the content itself. Only content that are "high enough" in the trees, and of the
+ /// specified content type, are returned.
+ public static IEnumerable Ancestors(this IPublishedContent content, int maxLevel)
where T : class, IPublishedContent
{
- return content.Ancestors(level).OfType();
+ return content.Ancestors(maxLevel).OfType();
}
+ ///
+ /// Gets the content and its ancestors.
+ ///
+ /// The content.
+ /// The content and its ancestors, in down-top order.
public static IEnumerable AncestorsOrSelf(this IPublishedContent content)
{
return content.AncestorsOrSelf(true, null);
}
- public static IEnumerable AncestorsOrSelf(this IPublishedContent content, int level)
+ ///
+ /// Gets the content and its ancestors, at a level lesser or equal to a specified level.
+ ///
+ /// The content.
+ /// The level.
+ /// The content and its ancestors, at a level lesser or equal to the specified level,
+ /// in down-top order.
+ /// Only content that are "high enough" in the tree are returned. So it may or may not begin
+ /// with the content itself, depending on its level.
+ public static IEnumerable AncestorsOrSelf(this IPublishedContent content, int maxLevel)
{
- return content.AncestorsOrSelf(true, n => n.Level <= level);
+ return content.AncestorsOrSelf(true, n => n.Level <= maxLevel);
}
+ ///
+ /// Gets the content and its ancestors, of a specified content type.
+ ///
+ /// The content.
+ /// The content type.
+ /// The content and its ancestors, of the specified content type, in down-top order.
+ /// May or may not begin with the content itself, depending on its content type.
public static IEnumerable AncestorsOrSelf(this IPublishedContent content, string contentTypeAlias)
{
return content.AncestorsOrSelf(true, n => n.DocumentTypeAlias == contentTypeAlias);
}
+ ///
+ /// Gets the content and its ancestors, of a specified content type.
+ ///
+ /// The content type.
+ /// The content.
+ /// The content and its ancestors, of the specified content type, in down-top order.
+ /// May or may not begin with the content itself, depending on its content type.
public static IEnumerable AncestorsOrSelf(this IPublishedContent content)
where T : class, IPublishedContent
{
return content.AncestorsOrSelf().OfType();
}
- public static IEnumerable AncestorsOrSelf(this IPublishedContent content, int level)
+ ///
+ /// Gets the content and its ancestor, at a lever lesser or equal to a specified level, and of a specified content type.
+ ///
+ /// The content type.
+ /// The content.
+ /// The level.
+ /// The content and its ancestors, at a level lesser or equal to the specified level, and of the specified
+ /// content type, in down-top order.
+ /// May or may not begin with the content itself, depending on its level and content type.
+ public static IEnumerable AncestorsOrSelf(this IPublishedContent content, int maxLevel)
where T : class, IPublishedContent
{
- return content.AncestorsOrSelf(level).OfType();
+ return content.AncestorsOrSelf(maxLevel).OfType();
}
+ ///
+ /// Gets the ancestor of the content, ie its parent.
+ ///
+ /// The content.
+ /// The ancestor of the content.
+ /// This method is here for consistency purposes but does not make much sense.
public static IPublishedContent Ancestor(this IPublishedContent content)
{
return content.Parent;
}
- public static IPublishedContent Ancestor(this IPublishedContent content, int level)
+ ///
+ /// Gets the nearest ancestor of the content, at a lever lesser or equal to a specified level.
+ ///
+ /// The content.
+ /// The level.
+ /// The nearest (in down-top order) ancestor of the content, at a level lesser or equal to the specified level.
+ /// Does not consider the content itself. May return null.
+ public static IPublishedContent Ancestor(this IPublishedContent content, int maxLevel)
{
- return content.EnumerateAncestors(false).FirstOrDefault(x => x.Level <= level);
+ return content.EnumerateAncestors(false).FirstOrDefault(x => x.Level <= maxLevel);
}
+ ///
+ /// Gets the nearest ancestor of the content, of a specified content type.
+ ///
+ /// The content.
+ /// The content type alias.
+ /// The nearest (in down-top order) ancestor of the content, of the specified content type.
+ /// Does not consider the content itself. May return null.
public static IPublishedContent Ancestor(this IPublishedContent content, string contentTypeAlias)
{
return content.EnumerateAncestors(false).FirstOrDefault(x => x.DocumentTypeAlias == contentTypeAlias);
}
+ ///
+ /// Gets the nearest ancestor of the content, of a specified content type.
+ ///
+ /// The content type.
+ /// The content.
+ /// The nearest (in down-top order) ancestor of the content, of the specified content type.
+ /// Does not consider the content itself. May return null.
public static T Ancestor(this IPublishedContent content)
where T : class, IPublishedContent
{
- return content.Ancestor() as T;
+ return content.Ancestors().FirstOrDefault();
}
- public static T Ancestor(this IPublishedContent content, int level)
+ ///
+ /// Gets the nearest ancestor of the content, at the specified level and of the specified content type.
+ ///
+ /// The content type.
+ /// The content.
+ /// The level.
+ /// The ancestor of the content, at the specified level and of the specified content type.
+ /// Does not consider the content itself. If the ancestor at the specified level is
+ /// not of the specified type, returns null.
+ public static T Ancestor(this IPublishedContent content, int maxLevel)
where T : class, IPublishedContent
{
- return content.Ancestor(level) as T;
+ return content.Ancestors(maxLevel).FirstOrDefault();
}
- // note: that one makes no sense and should return self -- but fixing that
- // would be a breaking change. Defining FIX_AXES would fix the situation.
+ ///
+ /// Gets the content or its nearest ancestor.
+ ///
+ /// The content.
+ /// The content.
+ /// This method is here for consistency purposes but does not make much sense.
public static IPublishedContent AncestorOrSelf(this IPublishedContent content)
{
-#if FIX_AXES
return content;
-#else
- return content.EnumerateAncestors(true).FirstOrDefault(x => x.Level == 1);
-#endif
}
- public static IPublishedContent AncestorOrSelf(this IPublishedContent content, int level)
+ ///
+ /// Gets the content or its nearest ancestor, at a lever lesser or equal to a specified level.
+ ///
+ /// The content.
+ /// The level.
+ /// The content or its nearest (in down-top order) ancestor, at a level lesser or equal to the specified level.
+ /// May or may not return the content itself depending on its level. May return null.
+ public static IPublishedContent AncestorOrSelf(this IPublishedContent content, int maxLevel)
{
- return content.EnumerateAncestors(true).FirstOrDefault(x => x.Level <= level);
+ return content.EnumerateAncestors(true).FirstOrDefault(x => x.Level <= maxLevel);
}
+ ///
+ /// Gets the content or its nearest ancestor, of a specified content type.
+ ///
+ /// The content.
+ /// The content type.
+ /// The content or its nearest (in down-top order) ancestor, of the specified content type.
+ /// May or may not return the content itself depending on its content type. May return null.
public static IPublishedContent AncestorOrSelf(this IPublishedContent content, string contentTypeAlias)
{
return content.EnumerateAncestors(true).FirstOrDefault(x => x.DocumentTypeAlias == contentTypeAlias);
}
+ ///
+ /// Gets the content or its nearest ancestor, of a specified content type.
+ ///
+ /// The content type.
+ /// The content.
+ /// The content or its nearest (in down-top order) ancestor, of the specified content type.
+ /// May or may not return the content itself depending on its content type. May return null.
public static T AncestorOrSelf(this IPublishedContent content)
where T : class, IPublishedContent
{
- return content.AncestorOrSelf() as T;
+ return content.AncestorsOrSelf().FirstOrDefault();
}
- public static T AncestorOrSelf(this IPublishedContent content, int level)
+ ///
+ /// Gets the content or its nearest ancestor, at a lever lesser or equal to a specified level, and of a specified content type.
+ ///
+ /// The content type.
+ /// The content.
+ /// The level.
+ ///
+ public static T AncestorOrSelf(this IPublishedContent content, int maxLevel)
where T : class, IPublishedContent
{
- return content.AncestorOrSelf(level) as T;
+ return content.AncestorsOrSelf(maxLevel).FirstOrDefault();
}
- // broken until we defined FIX_AXES
internal static IEnumerable AncestorsOrSelf(this IPublishedContent content, bool orSelf, Func func)
{
-#if FIX_AXES
- return content.EnumerateAncestors(orSelf).Where(x => func == null || func(x));
-#else
- var ancestors = new List();
-
- if (orSelf && (func == null || func(content)))
- ancestors.Add(content);
-
- while (content.Level > 1) // while we have a parent, consider the parent
- {
- content = content.Parent;
-
- if ((func == null || func(content)))
- ancestors.Add(content);
- }
-
- ancestors.Reverse();
- return ancestors;
-#endif
+ var ancestorsOrSelf = content.EnumerateAncestors(orSelf);
+ return func == null ? ancestorsOrSelf : ancestorsOrSelf.Where(func);
}
+ ///
+ /// Enumerates ancestors of the content, bottom-up.
+ ///
+ /// The content.
+ /// Indicates whether the content should be included.
+ /// Enumerates bottom-up ie walking up the tree (parent, grand-parent, etc).
internal static IEnumerable EnumerateAncestors(this IPublishedContent content, bool orSelf)
{
if (orSelf) yield return content;
@@ -1111,10 +1229,6 @@ namespace Umbraco.Web
// - every node occurs before all of its children and descendants.
// - the relative order of siblings is the order in which they occur in the children property of their parent node.
// - children and descendants occur before following siblings.
-
- // SO, here we want to implement a depth-first enumeration of children. Which is what EnumerateDescendants does, but NOT what
- // DescendantsOrSelf does, so basically descendants are NOT XPath-compliant in Umbraco at the moment -- but fixing that
- // would be a breaking change. Defining FIX_AXES would fix the situation.
public static IEnumerable Descendants(this IPublishedContent content)
{
@@ -1224,24 +1338,9 @@ namespace Umbraco.Web
return content.DescendantOrSelf(level) as T;
}
- // broken until we defined FIX_AXES
internal static IEnumerable DescendantsOrSelf(this IPublishedContent content, bool orSelf, Func func)
{
-#if FIX_AXES
return content.EnumerateDescendants(orSelf).Where(x => func == null || func(x));
-#else
- var init = (orSelf && (func == null || func(content))) ? new[] { content } : new IPublishedContent[] { };
-
- var descendants = init
- .Union(content.Children
- .FlattenList(x => x.Children)
- .Where(x => func == null || func(x))
- )
- .OrderBy(x => x.Level)
- .ThenBy(x => x.SortOrder);
-
- return descendants;
-#endif
}
internal static IEnumerable EnumerateDescendants(this IPublishedContent content, bool orSelf)
@@ -1279,9 +1378,6 @@ namespace Umbraco.Web
{
if (number < 0)
throw new ArgumentOutOfRangeException("number", "Must be greater than, or equal to, zero.");
-#if (!FIX_AXES)
- number += 1; // legacy is zero-based ie zero == parent
-#endif
return number == 0 ? content : content.EnumerateAncestors(false).Skip(number).FirstOrDefault();
}
@@ -1305,9 +1401,6 @@ namespace Umbraco.Web
{
if (number < 0)
throw new ArgumentOutOfRangeException("number", "Must be greater than, or equal to, zero.");
-#if (!FIX_AXES)
- number += 1; // legacy is zero-based ie zero == first child
-#endif
if (number == 0) return content;
content = content.Children.FirstOrDefault();
@@ -1348,9 +1441,6 @@ namespace Umbraco.Web
{
if (number < 0)
throw new ArgumentOutOfRangeException("number", "Must be greater than, or equal to, zero.");
-#if (!FIX_AXES)
- number += 1; // legacy is zero-based ie zero == next, whereas zero should be current
-#endif
return number == 0 ? content : content.ContentSet.ElementAtOrDefault(content.GetIndex() + number);
}
@@ -1418,10 +1508,6 @@ namespace Umbraco.Web
{
if (number < 0)
throw new ArgumentOutOfRangeException("number", "Must be greater than, or equal to, zero.");
-#if (!FIX_AXES)
- number = -number; // legacy wants negative numbers, should be positive
- number += 1; // legacy is zero-based ie zero == previous, whereas zero should be current
-#endif
return number == 0 ? content : content.ContentSet.ElementAtOrDefault(content.GetIndex() - number);
}