U4-6674 - Kill ToContentSet, becomes ToIndexedArray

This commit is contained in:
Stephan
2016-06-09 20:13:20 +02:00
parent cfa91f000b
commit be2d81154b
18 changed files with 626 additions and 1826 deletions
@@ -16,21 +16,6 @@ namespace Umbraco.Core.Models
/// </remarks>
public interface IPublishedContent
{
#region ContentSet
// Because of http://issues.umbraco.org/issue/U4-1797 and in order to implement
// Index() and methods that derive from it such as IsFirst(), IsLast(), etc... all
// content items must know about their containing content set.
/// <summary>
/// Gets the content set to which the content belongs.
/// </summary>
/// <remarks>The default set consists in the siblings of the content (including the content
/// itself) ordered by <c>sortOrder</c>.</remarks>
IEnumerable<IPublishedContent> ContentSet { get; }
#endregion
#region ContentType
/// <summary>
@@ -73,12 +58,6 @@ namespace Umbraco.Core.Models
/// have a published version, or not.</remarks>
bool IsDraft { get; }
/// <summary>
/// Gets the index of the published content within its current owning content set.
/// </summary>
/// <returns>The index of the published content within its current owning content set.</returns>
int GetIndex();
#endregion
#region Tree
@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Umbraco.Core.Models.PublishedContent
namespace Umbraco.Core.Models.PublishedContent
{
/// <summary>
/// Provides methods to handle extended content.
@@ -20,27 +15,5 @@ namespace Umbraco.Core.Models.PublishedContent
/// Gets a value indicating whether properties were added to the extended content.
/// </summary>
bool HasAddedProperties { get; }
/// <summary>
/// Sets the content set of the extended content.
/// </summary>
/// <param name="contentSet"></param>
void SetContentSet(IEnumerable<IPublishedContent> contentSet);
/// <summary>
/// Resets the content set of the extended content.
/// </summary>
void ClearContentSet();
/// <summary>
/// Sets the index of the extended content.
/// </summary>
/// <param name="value">The index value.</param>
void SetIndex(int value);
/// <summary>
/// Resets the index of the extended content.
/// </summary>
void ClearIndex();
}
}
@@ -0,0 +1,172 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Umbraco.Core.Models.PublishedContent
{
public class IndexedArrayItem<TContent>
{
public IndexedArrayItem(TContent content, int index)
{
Content = content;
Index = index;
}
public TContent Content { get; }
public int Index { get; }
public int TotalCount { get; internal set; }
public bool IsFirst()
{
return Index == 0;
}
public HtmlString IsFirst(string valueIfTrue)
{
return IsFirst(valueIfTrue, string.Empty);
}
public HtmlString IsFirst(string valueIfTrue, string valueIfFalse)
{
return new HtmlString(IsFirst() ? valueIfTrue : valueIfFalse);
}
public bool IsNotFirst()
{
return IsFirst() == false;
}
public HtmlString IsNotFirst(string valueIfTrue)
{
return IsNotFirst(valueIfTrue, string.Empty);
}
public HtmlString IsNotFirst(string valueIfTrue, string valueIfFalse)
{
return new HtmlString(IsNotFirst() ? valueIfTrue : valueIfFalse);
}
public bool IsIndex(int index)
{
return Index == index;
}
public HtmlString IsIndex(int index, string valueIfTrue)
{
return IsIndex(index, valueIfTrue, string.Empty);
}
public HtmlString IsIndex(int index, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(IsIndex(index) ? valueIfTrue : valueIfFalse);
}
public bool IsModZero(int modulus)
{
return Index % modulus == 0;
}
public HtmlString IsModZero(int modulus, string valueIfTrue)
{
return IsModZero(modulus, valueIfTrue, string.Empty);
}
public HtmlString IsModZero(int modulus, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(IsModZero(modulus) ? valueIfTrue : valueIfFalse);
}
public bool IsNotModZero(int modulus)
{
return IsModZero(modulus) == false;
}
public HtmlString IsNotModZero(int modulus, string valueIfTrue)
{
return IsNotModZero(modulus, valueIfTrue, string.Empty);
}
public HtmlString IsNotModZero(int modulus, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(IsNotModZero(modulus) ? valueIfTrue : valueIfFalse);
}
public bool IsNotIndex(int index)
{
return IsIndex(index) == false;
}
public HtmlString IsNotIndex(int index, string valueIfTrue)
{
return IsNotIndex(index, valueIfTrue, string.Empty);
}
public HtmlString IsNotIndex(int index, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(IsNotIndex(index) ? valueIfTrue : valueIfFalse);
}
public bool IsLast()
{
return Index == TotalCount - 1;
}
public HtmlString IsLast(string valueIfTrue)
{
return IsLast(valueIfTrue, string.Empty);
}
public HtmlString IsLast(string valueIfTrue, string valueIfFalse)
{
return new HtmlString(IsLast() ? valueIfTrue : valueIfFalse);
}
public bool IsNotLast()
{
return IsLast() == false;
}
public HtmlString IsNotLast(string valueIfTrue)
{
return IsNotLast(valueIfTrue, string.Empty);
}
public HtmlString IsNotLast(string valueIfTrue, string valueIfFalse)
{
return new HtmlString(IsNotLast() ? valueIfTrue : valueIfFalse);
}
public bool IsEven()
{
return Index % 2 == 0;
}
public HtmlString IsEven(string valueIfTrue)
{
return IsEven(valueIfTrue, string.Empty);
}
public HtmlString IsEven(string valueIfTrue, string valueIfFalse)
{
return new HtmlString(IsEven() ? valueIfTrue : valueIfFalse);
}
public bool IsOdd()
{
return Index % 2 == 1;
}
public HtmlString IsOdd(string valueIfTrue)
{
return IsOdd(valueIfTrue, string.Empty);
}
public HtmlString IsOdd(string valueIfTrue, string valueIfFalse)
{
return new HtmlString(IsOdd() ? valueIfTrue : valueIfFalse);
}
}
}
@@ -17,31 +17,9 @@ namespace Umbraco.Core.Models.PublishedContent
#endregion
#region Index
private int? _index;
public override int GetIndex()
{
// fast
if (_index.HasValue) return _index.Value;
// slow -- and don't cache, not in a set
if (_contentSet == null) return Content.GetIndex();
// slow -- but cache for next time
var index = _contentSet.FindIndex(x => x.Id == Id);
if (index < 0)
throw new IndexOutOfRangeException("Could not find content in the content set.");
_index = index;
return index;
}
#endregion
#region Extend
internal static IPublishedContentExtended Extend(IPublishedContent content, IEnumerable<IPublishedContent> contentSet)
internal static IPublishedContentExtended Extend(IPublishedContent content)
{
// first unwrap content down to the lowest possible level, ie either the deepest inner
// IPublishedContent or the first extended that has added properties. this is to avoid
@@ -95,7 +73,6 @@ namespace Umbraco.Core.Models.PublishedContent
var extended2 = extended as IPublishedContentExtended;
if (extended2 == null)
throw new Exception("Extended does not implement IPublishedContentExtended.");
extended2.SetContentSet(contentSet);
return extended2;
}
@@ -115,37 +92,6 @@ namespace Umbraco.Core.Models.PublishedContent
get { return _properties != null; }
}
void IPublishedContentExtended.SetContentSet(IEnumerable<IPublishedContent> contentSet)
{
_contentSet = contentSet;
}
void IPublishedContentExtended.ClearContentSet()
{
_contentSet = null;
}
void IPublishedContentExtended.SetIndex(int value)
{
_index = value;
}
void IPublishedContentExtended.ClearIndex()
{
_index = null;
}
#endregion
#region Content set
private IEnumerable<IPublishedContent> _contentSet;
public override IEnumerable<IPublishedContent> ContentSet
{
get { return _contentSet ?? Content.ContentSet; }
}
#endregion
#region Properties
@@ -1,32 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Umbraco.Core.Models.PublishedContent
{
/// <summary>
/// Represents an ordered set of <see cref="IPublishedContent"/>.
/// </summary>
/// <typeparam name="T">The type of content.</typeparam>
public class PublishedContentOrderedSet<T> : PublishedContentSet<T>, IOrderedEnumerable<T>
where T : class, IPublishedContent
{
// ReSharper disable ParameterTypeCanBeEnumerable.Local
internal PublishedContentOrderedSet(IOrderedEnumerable<T> content)
// ReSharper restore ParameterTypeCanBeEnumerable.Local
: base(content)
{ }
// note: because we implement IOrderedEnumerable, we don't need to implement the ThenBy nor
// ThenByDescending methods here, only CreateOrderedEnumerable and that does it.
#region IOrderedEnumerable<T>
public IOrderedEnumerable<T> CreateOrderedEnumerable<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer, bool descending)
{
return new PublishedContentOrderedSet<T>(((IOrderedEnumerable<T>)Source).CreateOrderedEnumerable(keySelector, comparer, descending));
}
#endregion
}
}
@@ -1,234 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Umbraco.Core.Models.PublishedContent
{
/// <summary>
/// Represents a set of <see cref="IPublishedContent"/>.
/// </summary>
/// <typeparam name="T">The type of content.</typeparam>
/// <remarks>
/// <para>A <c>ContentSet{T}</c> is created from an <c>IEnumerable{T}</c> using the <c>ToContentSet</c>
/// extension method.</para>
/// <para>The content set source is enumerated only once. Same as what you get
/// when you call ToList on an IEnumerable. Only, ToList enumerates its source when
/// created, whereas a content set enumerates its source only when the content set itself
/// is enumerated.</para>
/// </remarks>
public class PublishedContentSet<T> : IEnumerable<T>
where T : class, IPublishedContent
{
// used by <c>ToContentSet</c> extension method to initialize a new set from an IEnumerable.
internal PublishedContentSet(IEnumerable<T> source)
{
if (source == null)
throw new ArgumentNullException("source");
Source = source;
}
#region Source
protected readonly IEnumerable<T> Source;
#endregion
#region Enumerated
// cache the enumeration so we don't enumerate more than once. Same as what you get
// when you call ToList on an IEnumerable. Only, ToList enumerates its source when
// created, whereas a content set enumerates its source only when the content set itself
// is enumerated.
// cache the wrapped items so if we reset the enumeration, we do not re-wrap everything (only new items).
private T[] _enumerated;
private readonly Dictionary<T, IPublishedContentExtended> _xContent = new Dictionary<T, IPublishedContentExtended>();
// wrap an item, ie create the actual clone for this set
private T MapContentAsT(T t)
{
return MapContent(t) as T;
}
internal IPublishedContentExtended MapContent(T t)
{
IPublishedContentExtended extend;
if (_xContent.TryGetValue(t, out extend)) return extend;
extend = PublishedContentExtended.Extend(t, this);
var asT = extend as T;
if (asT == null)
throw new InvalidOperationException(string.Format("Failed extend a published content of type {0}."
+ "Got {1} when expecting {2}.", t.GetType().FullName, extend.GetType().FullName, typeof(T).FullName));
_xContent[t] = extend;
return extend;
}
private T[] Enumerated
{
get
{
// enumerate the source and cache the result
// tell clones about their index within the set (for perfs purposes)
var index = 0;
return _enumerated ?? (_enumerated = Source.Select(t =>
{
var extend = MapContent(t);
extend.SetIndex(index++);
return extend as T;
}).ToArray());
}
}
// indicates that the source has changed
// so the set can clear its inner caches
// should only be used by DynamicPublishedContentList
internal void SourceChanged()
{
// reset the cached enumeration so it's enumerated again
if (_enumerated == null) return;
_enumerated = null;
foreach (var item in _xContent.Values)
item.ClearIndex();
var removed = _xContent.Keys.Except(Source);
foreach (var content in removed)
{
_xContent[content].ClearContentSet();
_xContent.Remove(content);
}
}
/// <summary>
/// Gets the number of items in the set.
/// </summary>
/// <returns>The number of items in the set.</returns>
/// <remarks>Will cause the set to be enumerated if it hasn't been already.</remarks>
public virtual int Count
{
get { return Enumerated.Length; }
}
#endregion
#region IEnumerable<T>
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>)Enumerated).GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
#region Wrap methods returning T
public T ElementAt(int index)
{
return MapContentAsT(Source.ElementAt(index));
}
public T ElementAtOrDefault(int index)
{
var element = Source.ElementAtOrDefault(index);
return element == null ? null : MapContentAsT(element);
}
public T First()
{
return MapContentAsT(Source.First());
}
public T First(Func<T, bool> predicate)
{
return MapContentAsT(Source.First(predicate));
}
public T FirstOrDefault()
{
var first = Source.FirstOrDefault();
return first == null ? null : MapContentAsT(first);
}
public T FirstOrDefault(Func<T, bool> predicate)
{
var first = Source.FirstOrDefault(predicate);
return first == null ? null : MapContentAsT(first);
}
public T Last()
{
return MapContentAsT(Source.Last());
}
public T Last(Func<T, bool> predicate)
{
return MapContentAsT(Source.Last(predicate));
}
public T LastOrDefault()
{
var last = Source.LastOrDefault();
return last == null ? null : MapContentAsT(last);
}
public T LastOrDefault(Func<T, bool> predicate)
{
var last = Source.LastOrDefault(predicate);
return last == null ? null : MapContentAsT(last);
}
public T Single()
{
return MapContentAsT(Source.Single());
}
public T Single(Func<T, bool> predicate)
{
return MapContentAsT(Source.Single(predicate));
}
public T SingleOrDefault()
{
var single = Source.SingleOrDefault();
return single == null ? null : MapContentAsT(single);
}
public T SingleOrDefault(Func<T, bool> predicate)
{
var single = Source.SingleOrDefault(predicate);
return single == null ? null : MapContentAsT(single);
}
#endregion
#region Wrap methods returning IOrderedEnumerable<T>
public PublishedContentOrderedSet<T> OrderBy<TKey>(Func<T, TKey> keySelector)
{
return new PublishedContentOrderedSet<T>(Source.OrderBy(keySelector));
}
public PublishedContentOrderedSet<T> OrderBy<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer)
{
return new PublishedContentOrderedSet<T>(Source.OrderBy(keySelector, comparer));
}
public PublishedContentOrderedSet<T> OrderByDescending<TKey>(Func<T, TKey> keySelector)
{
return new PublishedContentOrderedSet<T>(Source.OrderByDescending(keySelector));
}
public PublishedContentOrderedSet<T> OrderByDescending<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer)
{
return new PublishedContentOrderedSet<T>(Source.OrderByDescending(keySelector, comparer));
}
#endregion
}
}
@@ -48,12 +48,6 @@ namespace Umbraco.Core.Models.PublishedContent
return Content;
}
#region ContentSet
public virtual IEnumerable<IPublishedContent> ContentSet => Content.ContentSet;
#endregion
#region ContentType
public virtual PublishedContentType ContentType => Content.ContentType;
@@ -102,11 +96,6 @@ namespace Umbraco.Core.Models.PublishedContent
public virtual bool IsDraft => Content.IsDraft;
public virtual int GetIndex()
{
return Content.GetIndex();
}
#endregion
#region Tree
+1 -2
View File
@@ -627,8 +627,7 @@
<Compile Include="PropertyEditors\ValueConverters\TextStringValueConverter.cs" />
<Compile Include="PropertyEditors\ValueConverters\TinyMceValueConverter.cs" />
<Compile Include="PropertyEditors\IPropertyValueConverter.cs" />
<Compile Include="Models\PublishedContent\PublishedContentOrderedSet.cs" />
<Compile Include="Models\PublishedContent\PublishedContentSet.cs" />
<Compile Include="Models\PublishedContent\IndexedArrayItem.cs" />
<Compile Include="Strings\Css\StylesheetRule.cs" />
<Compile Include="Models\DictionaryItem.cs" />
<Compile Include="Models\DictionaryTranslation.cs" />
File diff suppressed because it is too large Load Diff
@@ -91,75 +91,39 @@ namespace Umbraco.Tests.PublishedContent
Assert.AreEqual("Content 1", content.Name);
}
[Test]
public void DefaultContentSetIsSiblings()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot().First();
Assert.AreEqual(0, content.Index());
Assert.IsTrue(content.IsFirst());
}
[Test]
public void RunOnLatestContentSet()
{
// get first content
var content = UmbracoContext.Current.ContentCache.GetAtRoot().First();
var id = content.Id;
Assert.IsTrue(content.IsFirst());
// reverse => should be last, but set has not changed => still first
content = UmbracoContext.Current.ContentCache.GetAtRoot().Reverse().First(x => x.Id == id);
Assert.IsTrue(content.IsFirst());
Assert.IsFalse(content.IsLast());
// reverse + new set => now it's last
content = UmbracoContext.Current.ContentCache.GetAtRoot().Reverse().ToContentSet().First(x => x.Id == id);
Assert.IsFalse(content.IsFirst());
Assert.IsTrue(content.IsLast());
// reverse that set => should be first, but no new set => still last
content = UmbracoContext.Current.ContentCache.GetAtRoot().Reverse().ToContentSet().Reverse().First(x => x.Id == id);
Assert.IsFalse(content.IsFirst());
Assert.IsTrue(content.IsLast());
}
[Test]
public void Distinct()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot()
var items = UmbracoContext.Current.ContentCache.GetAtRoot()
.Distinct()
.Distinct()
.ToContentSet()
.First();
.ToIndexedArray();
Assert.AreEqual("Content 1", content.Name);
Assert.IsTrue(content.IsFirst());
Assert.IsFalse(content.IsLast());
var item = items[0];
Assert.AreEqual("Content 1", item.Content.Name);
Assert.IsTrue(item.IsFirst());
Assert.IsFalse(item.IsLast());
content = content.Next();
Assert.AreEqual("Content 2", content.Name);
Assert.IsFalse(content.IsFirst());
Assert.IsFalse(content.IsLast());
item = items[1];
Assert.AreEqual("Content 2", item.Content.Name);
Assert.IsFalse(item.IsFirst());
Assert.IsFalse(item.IsLast());
content = content.Next();
Assert.AreEqual("Content 2Sub", content.Name);
Assert.IsFalse(content.IsFirst());
Assert.IsTrue(content.IsLast());
item = items[2];
Assert.AreEqual("Content 2Sub", item.Content.Name);
Assert.IsFalse(item.IsFirst());
Assert.IsTrue(item.IsLast());
}
[Test]
public void OfType1()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot()
var items = UmbracoContext.Current.ContentCache.GetAtRoot()
.OfType<ContentType2>()
.Distinct()
.ToArray();
Assert.AreEqual(2, content.Count());
Assert.IsInstanceOf<ContentType2>(content.First());
var set = content.ToContentSet();
Assert.IsInstanceOf<ContentType2>(set.First());
Assert.AreSame(set, set.First().ContentSet);
Assert.IsInstanceOf<ContentType2Sub>(set.First().Next());
.ToIndexedArray();
Assert.AreEqual(2, items.Length);
Assert.IsInstanceOf<ContentType2>(items.First().Content);
}
[Test]
@@ -168,11 +132,9 @@ namespace Umbraco.Tests.PublishedContent
var content = UmbracoContext.Current.ContentCache.GetAtRoot()
.OfType<ContentType2Sub>()
.Distinct()
.ToArray();
Assert.AreEqual(1, content.Count());
Assert.IsInstanceOf<ContentType2Sub>(content.First());
var set = content.ToContentSet();
Assert.IsInstanceOf<ContentType2Sub>(set.First());
.ToIndexedArray();
Assert.AreEqual(1, content.Length);
Assert.IsInstanceOf<ContentType2Sub>(content.First().Content);
}
[Test]
@@ -188,17 +150,16 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Position()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot()
var items = UmbracoContext.Current.ContentCache.GetAtRoot()
.Where(x => x.GetPropertyValue<int>("prop1") == 1234)
.ToContentSet()
.ToArray();
.ToIndexedArray();
Assert.IsTrue(content.First().IsFirst());
Assert.IsFalse(content.First().IsLast());
Assert.IsFalse(content.First().Next().IsFirst());
Assert.IsFalse(content.First().Next().IsLast());
Assert.IsFalse(content.First().Next().Next().IsFirst());
Assert.IsTrue(content.First().Next().Next().IsLast());
Assert.IsTrue(items.First().IsFirst());
Assert.IsFalse(items.First().IsLast());
Assert.IsFalse(items.Skip(1).First().IsFirst());
Assert.IsFalse(items.Skip(1).First().IsLast());
Assert.IsFalse(items.Skip(2).First().IsFirst());
Assert.IsTrue(items.Skip(2).First().IsLast());
}
[Test]
@@ -199,14 +199,6 @@ namespace Umbraco.Tests.PublishedContent
public PublishedItemType ItemType { get { return PublishedItemType.Content; } }
public bool IsDraft { get; set; }
public int GetIndex()
{
var index = this.Siblings().FindIndex(x => x.Id == Id);
if (index < 0)
throw new IndexOutOfRangeException("Failed to find content in its siblings collection?!");
return index;
}
#endregion
#region Tree
@@ -219,12 +211,6 @@ namespace Umbraco.Tests.PublishedContent
#endregion
#region ContentSet
public IEnumerable<IPublishedContent> ContentSet { get { return this.Siblings(); } }
#endregion
#region ContentType
public PublishedContentType ContentType { get; private set; }
@@ -118,49 +118,16 @@ namespace Umbraco.Tests.PublishedContent
return doc;
}
[Test]
[Ignore("IPublishedContent currently (6.1 as of april 25, 2013) has bugs")]
public void Fails()
{
var content = GetNode(1173);
var c1 = content.Children.First(x => x.Id == 1177);
Assert.IsFalse(c1.IsFirst());
var c2 = content.Children.Where(x => x.DocumentTypeAlias == "CustomDocument").First(x => x.Id == 1177);
Assert.IsTrue(c2.IsFirst());
// First is not implemented
var c2a = content.Children.First(x => x.DocumentTypeAlias == "CustomDocument" && x.Id == 1177);
Assert.IsTrue(c2a.IsFirst()); // so here it's luck
c1 = content.Children.First(x => x.Id == 1177);
Assert.IsFalse(c1.IsFirst()); // and here it fails
// but even using supported (where) method...
// do not replace by First(x => ...) here since it's not supported at the moment
c1 = content.Children.Where(x => x.Id == 1177).First();
c2 = content.Children.Where(x => x.DocumentTypeAlias == "CustomDocument" && x.Id == 1177).First();
Assert.IsFalse(c1.IsFirst()); // here it fails because c2 has corrupted it
// so there's only 1 IPublishedContent instance
// which keeps changing collection, ie being modified
// which is *bad* from a cache point of vue
// and from a consistency point of vue...
// => we want clones!
}
[Test]
public void Is_Last_From_Where_Filter_Dynamic_Linq()
{
var doc = GetNode(1173);
var items = doc.Children.Where("Visible").ToContentSet();
var items = doc.Children.Where("Visible").ToIndexedArray();
foreach (var item in items)
{
if (item.Id != 1178)
if (item.Content.Id != 1178)
{
Assert.IsFalse(item.IsLast());
}
@@ -179,13 +146,13 @@ namespace Umbraco.Tests.PublishedContent
var items = doc
.Children
.Where(x => x.IsVisible())
.ToContentSet();
.ToIndexedArray();
Assert.AreEqual(3, items.Count());
Assert.AreEqual(3, items.Length);
foreach (var d in items)
{
switch (d.Id)
switch (d.Content.Id)
{
case 1174:
Assert.IsTrue(d.IsFirst());
@@ -228,14 +195,13 @@ namespace Umbraco.Tests.PublishedContent
.OfType<Home>() // ours, return IEnumerable<Home> (actually a PublishedContentSet<Home>)
.Where(x => x.IsVisible()) // so, here it's linq again :-(
.ToContentSet() // so, we need that one for the test to pass
.ToArray();
.ToIndexedArray(); // so, we need that one for the test to pass
Assert.AreEqual(1, items.Count());
foreach (var d in items)
{
switch (d.Id)
switch (d.Content.Id)
{
case 1174:
Assert.IsTrue(d.IsFirst());
@@ -253,11 +219,11 @@ namespace Umbraco.Tests.PublishedContent
{
var doc = GetNode(1173);
var items = doc.Children.Take(3).ToContentSet();
var items = doc.Children.Take(3).ToIndexedArray();
foreach (var item in items)
{
if (item.Id != 1178)
if (item.Content.Id != 1178)
{
Assert.IsFalse(item.IsLast());
}
@@ -273,9 +239,9 @@ namespace Umbraco.Tests.PublishedContent
{
var doc = GetNode(1173);
foreach (var d in doc.Children.Skip(1))
foreach (var d in doc.Children.Skip(1).ToIndexedArray())
{
if (d.Id != 1176)
if (d.Content.Id != 1176)
{
Assert.IsFalse(d.IsLast());
}
@@ -293,11 +259,11 @@ namespace Umbraco.Tests.PublishedContent
var items = doc.Children
.Concat(new[] { GetNode(1175), GetNode(4444) })
.ToContentSet();
.ToIndexedArray();
foreach (var item in items)
{
if (item.Id != 4444)
if (item.Content.Id != 4444)
{
Assert.IsFalse(item.IsLast());
}
@@ -362,58 +328,6 @@ namespace Umbraco.Tests.PublishedContent
Assert.IsNotNull(result);
}
[Test]
public void Index()
{
var doc = GetNode(1173);
Assert.AreEqual(0, doc.Index());
doc = GetNode(1176);
Assert.AreEqual(3, doc.Index());
doc = GetNode(1177);
Assert.AreEqual(1, doc.Index());
doc = GetNode(1178);
Assert.AreEqual(2, doc.Index());
}
[Test]
public void Is_First()
{
var doc = GetNode(1046); //test root nodes
Assert.IsTrue(doc.IsFirst());
doc = GetNode(1172);
Assert.IsFalse(doc.IsFirst());
doc = GetNode(1173); //test normal nodes
Assert.IsTrue(doc.IsFirst());
doc = GetNode(1175);
Assert.IsFalse(doc.IsFirst());
}
[Test]
public void Is_Not_First()
{
var doc = GetNode(1046); //test root nodes
Assert.IsFalse(doc.IsNotFirst());
doc = GetNode(1172);
Assert.IsTrue(doc.IsNotFirst());
doc = GetNode(1173); //test normal nodes
Assert.IsFalse(doc.IsNotFirst());
doc = GetNode(1175);
Assert.IsTrue(doc.IsNotFirst());
}
[Test]
public void Is_Position()
{
var doc = GetNode(1046); //test root nodes
Assert.IsTrue(doc.IsPosition(0));
doc = GetNode(1172);
Assert.IsTrue(doc.IsPosition(1));
doc = GetNode(1173); //test normal nodes
Assert.IsTrue(doc.IsPosition(0));
doc = GetNode(1175);
Assert.IsTrue(doc.IsPosition(1));
}
[Test]
public void Children_GroupBy_DocumentTypeAlias()
{
@@ -617,46 +531,6 @@ namespace Umbraco.Tests.PublishedContent
Assert.AreEqual((int)1174, (int)result.Id);
}
[Test]
public void Next()
{
var doc = GetNode(1173);
var result = doc.Next();
Assert.IsNotNull(result);
Assert.AreEqual((int)1175, (int)result.Id);
}
[Test]
public void Next_Without_Sibling()
{
var doc = GetNode(1176);
Assert.IsNull(doc.Next());
}
[Test]
public void Previous_Without_Sibling()
{
var doc = GetNode(1173);
Assert.IsNull(doc.Previous());
}
[Test]
public void Previous()
{
var doc = GetNode(1176);
var result = doc.Previous();
Assert.IsNotNull(result);
Assert.AreEqual((int)1178, (int)result.Id);
}
[Test]
public void DetachedProperty1()
{
@@ -22,10 +22,6 @@ namespace Umbraco.Tests.PublishedContent
Assert.AreEqual(1, content.Level);
Assert.IsNull(content.Parent);
// and yet is has siblings, etc.
var siblings = content.Siblings();
Assert.AreEqual(2, siblings.Count());
// non-existing content is null
content = ctx.ContentCache.GetById(666);
Assert.IsNull(content);
+6 -6
View File
@@ -14,14 +14,13 @@ namespace Umbraco.Web
/// </summary>
internal static class ExamineExtensions
{
internal static PublishedContentSet<IPublishedContent> ConvertSearchResultToPublishedContent(this IEnumerable<SearchResult> results, IPublishedCache cache)
internal static IEnumerable<IPublishedContent> ConvertSearchResultToPublishedContent(this IEnumerable<SearchResult> results, IPublishedCache cache)
{
//TODO: The search result has already returned a result which SHOULD include all of the data to create an IPublishedContent,
// however this is currently not the case:
// http://examine.codeplex.com/workitem/10350
var list = new List<IPublishedContent>();
var set = new PublishedContentSet<IPublishedContent>(list);
foreach (var result in results.OrderByDescending(x => x.Score))
{
@@ -36,16 +35,17 @@ namespace Umbraco.Web
// returned by the cache, in case the cache can create real types.
// so we have to ask it to please extend itself.
list.Add(content);
var extend = set.MapContent(content);
//var extend = set.MapContent(content);
var extend = PublishedContentExtended.Extend(content);
list.Add(extend);
var property = new PropertyResult("examineScore",
var property = new PropertyResult("examineScore",
result.Score,
PropertyResultType.CustomProperty);
extend.AddProperty(property);
}
return set;
return list;
}
}
}
@@ -28,13 +28,6 @@ namespace Umbraco.Web.Models
protected internal IPublishedContent PublishedContent { get; private set; }
private DynamicPublishedContentList _contentList;
// must implement that one if we implement IPublishedContent
public IEnumerable<IPublishedContent> ContentSet
{
// that is a definitively non-efficient way of doing it, though it should work
get { return _contentList ?? (_contentList = new DynamicPublishedContentList(PublishedContent.ContentSet)); }
}
public PublishedContentType ContentType { get { return PublishedContent.ContentType; } }
#region Constructors
@@ -435,11 +428,6 @@ namespace Umbraco.Web.Models
get { return PublishedContent.IsDraft; }
}
int IPublishedContent.GetIndex()
{
return PublishedContent.GetIndex();
}
ICollection<IPublishedProperty> IPublishedContent.Properties
{
get { return PublishedContent.Properties; }
@@ -775,20 +763,6 @@ namespace Umbraco.Web.Models
#endregion
#region IPublishedContente extension methods - ContentSet
public int Position()
{
return Index();
}
public int Index()
{
return PublishedContent.GetIndex();
}
#endregion
#region IPublishedContent extension methods - IsSomething: misc
public bool Visible
@@ -818,160 +792,6 @@ namespace Umbraco.Web.Models
#endregion
#region IPublishedContent extension methods - IsSomething: position in set
public bool IsFirst()
{
return PublishedContent.IsFirst();
}
public HtmlString IsFirst(string valueIfTrue)
{
return PublishedContent.IsFirst(valueIfTrue);
}
public HtmlString IsFirst(string valueIfTrue, string valueIfFalse)
{
return PublishedContent.IsFirst(valueIfTrue, valueIfFalse);
}
public bool IsNotFirst()
{
return PublishedContent.IsNotFirst();
}
public HtmlString IsNotFirst(string valueIfTrue)
{
return PublishedContent.IsNotFirst(valueIfTrue);
}
public HtmlString IsNotFirst(string valueIfTrue, string valueIfFalse)
{
return PublishedContent.IsNotFirst(valueIfTrue, valueIfFalse);
}
public bool IsPosition(int index)
{
return PublishedContent.IsPosition(index);
}
public HtmlString IsPosition(int index, string valueIfTrue)
{
return PublishedContent.IsPosition(index, valueIfTrue);
}
public HtmlString IsPosition(int index, string valueIfTrue, string valueIfFalse)
{
return PublishedContent.IsPosition(index, valueIfTrue, valueIfFalse);
}
public bool IsModZero(int modulus)
{
return PublishedContent.IsModZero(modulus);
}
public HtmlString IsModZero(int modulus, string valueIfTrue)
{
return PublishedContent.IsModZero(modulus, valueIfTrue);
}
public HtmlString IsModZero(int modulus, string valueIfTrue, string valueIfFalse)
{
return PublishedContent.IsModZero(modulus, valueIfTrue, valueIfFalse);
}
public bool IsNotModZero(int modulus)
{
return PublishedContent.IsNotModZero(modulus);
}
public HtmlString IsNotModZero(int modulus, string valueIfTrue)
{
return PublishedContent.IsNotModZero(modulus, valueIfTrue);
}
public HtmlString IsNotModZero(int modulus, string valueIfTrue, string valueIfFalse)
{
return PublishedContent.IsNotModZero(modulus, valueIfTrue, valueIfFalse);
}
public bool IsNotPosition(int index)
{
return PublishedContent.IsNotPosition(index);
}
public HtmlString IsNotPosition(int index, string valueIfTrue)
{
return PublishedContent.IsNotPosition(index, valueIfTrue);
}
public HtmlString IsNotPosition(int index, string valueIfTrue, string valueIfFalse)
{
return PublishedContent.IsNotPosition(index, valueIfTrue, valueIfFalse);
}
public bool IsLast()
{
return PublishedContent.IsLast();
}
public HtmlString IsLast(string valueIfTrue)
{
return PublishedContent.IsLast(valueIfTrue);
}
public HtmlString IsLast(string valueIfTrue, string valueIfFalse)
{
return PublishedContent.IsLast(valueIfTrue, valueIfFalse);
}
public bool IsNotLast()
{
return PublishedContent.IsNotLast();
}
public HtmlString IsNotLast(string valueIfTrue)
{
return PublishedContent.IsNotLast(valueIfTrue);
}
public HtmlString IsNotLast(string valueIfTrue, string valueIfFalse)
{
return PublishedContent.IsNotLast(valueIfTrue, valueIfFalse);
}
public bool IsEven()
{
return PublishedContent.IsEven();
}
public HtmlString IsEven(string valueIfTrue)
{
return PublishedContent.IsEven(valueIfTrue);
}
public HtmlString IsEven(string valueIfTrue, string valueIfFalse)
{
return PublishedContent.IsEven(valueIfTrue, valueIfFalse);
}
public bool IsOdd()
{
return PublishedContent.IsOdd();
}
public HtmlString IsOdd(string valueIfTrue)
{
return PublishedContent.IsOdd(valueIfTrue);
}
public HtmlString IsOdd(string valueIfTrue, string valueIfFalse)
{
return PublishedContent.IsOdd(valueIfTrue, valueIfFalse);
}
#endregion
#region IPublishedContent extension methods - IsSomething: equality
public bool IsEqual(DynamicPublishedContent other)
@@ -1209,46 +1029,6 @@ namespace Umbraco.Web.Models
return PublishedContent.Down(contentTypeAlias).AsDynamicOrNull();
}
public DynamicPublishedContent Next()
{
return PublishedContent.Next().AsDynamicOrNull();
}
public DynamicPublishedContent Next(int number)
{
return PublishedContent.Next(number).AsDynamicOrNull();
}
public DynamicPublishedContent Next(string contentTypeAlias)
{
return PublishedContent.Next(contentTypeAlias).AsDynamicOrNull();
}
public DynamicPublishedContent Previous()
{
return PublishedContent.Previous().AsDynamicOrNull();
}
public DynamicPublishedContent Previous(int number)
{
return PublishedContent.Previous(number).AsDynamicOrNull();
}
public DynamicPublishedContent Previous(string contentTypeAlias)
{
return PublishedContent.Previous(contentTypeAlias).AsDynamicOrNull();
}
public DynamicPublishedContent Sibling(int number)
{
return PublishedContent.Previous(number).AsDynamicOrNull();
}
public DynamicPublishedContent Sibling(string contentTypeAlias)
{
return PublishedContent.Previous(contentTypeAlias).AsDynamicOrNull();
}
#endregion
#region Parent
@@ -19,7 +19,6 @@ namespace Umbraco.Web.Models
public class DynamicPublishedContentList : DynamicObject, IEnumerable<DynamicPublishedContent>
{
private readonly List<IPublishedContent> _content;
private readonly PublishedContentSet<IPublishedContent> _contentSet;
internal readonly List<DynamicPublishedContent> Items;
#region Constructor
@@ -27,22 +26,19 @@ namespace Umbraco.Web.Models
public DynamicPublishedContentList()
{
_content = new List<IPublishedContent>();
_contentSet = new PublishedContentSet<IPublishedContent>(_content);
Items = new List<DynamicPublishedContent>();
}
public DynamicPublishedContentList(IEnumerable<IPublishedContent> items)
{
_content = items.ToList();
_contentSet = new PublishedContentSet<IPublishedContent>(_content);
Items = _contentSet.Select(x => new DynamicPublishedContent(x, this)).ToList();
Items = _content.Select(x => new DynamicPublishedContent(x, this)).ToList();
}
public DynamicPublishedContentList(IEnumerable<DynamicPublishedContent> items)
{
_content = items.Select(x => x.PublishedContent).ToList();
_contentSet = new PublishedContentSet<IPublishedContent>(_content);
Items = _contentSet.Select(x => new DynamicPublishedContent(x, this)).ToList();
Items = _content.Select(x => new DynamicPublishedContent(x, this)).ToList();
}
#endregion
@@ -67,10 +63,7 @@ namespace Umbraco.Web.Models
{
var content = dynamicContent.PublishedContent;
_content.Add(content);
_contentSet.SourceChanged();
var setContent = _contentSet.MapContent(content);
Items.Add(new DynamicPublishedContent(setContent, this));
Items.Add(new DynamicPublishedContent(content, this));
}
/// <summary>
@@ -82,7 +75,6 @@ namespace Umbraco.Web.Models
if (Items.Contains(dynamicContent) == false) return;
Items.Remove(dynamicContent);
_content.Remove(dynamicContent.PublishedContent);
_contentSet.SourceChanged();
}
#endregion
@@ -115,14 +115,6 @@ namespace Umbraco.Web.Models
public abstract bool IsDraft { get; }
public int GetIndex()
{
var index = this.Siblings().FindIndex(x => x.Id == Id);
if (index < 0)
throw new IndexOutOfRangeException("Could not find content in the content set.");
return index;
}
#endregion
#region Tree
@@ -140,16 +132,6 @@ namespace Umbraco.Web.Models
#endregion
#region ContentSet
public virtual IEnumerable<IPublishedContent> ContentSet
{
// the default content set of a content is its siblings
get { return this.Siblings(); }
}
#endregion
#region ContentType
public abstract PublishedContentType ContentType { get; }
+6 -440
View File
@@ -452,28 +452,14 @@ namespace Umbraco.Web
#endregion
#region ToContentSet
#region ToIndexedArray
/// <summary>
/// Returns the content enumerable as a content set.
/// </summary>
/// <param name="source">The content enumerable.</param>
/// <returns>A content set wrapping the content enumerable.</returns>
public static PublishedContentSet<T> ToContentSet<T>(this IEnumerable<T> source)
where T : class, IPublishedContent
public static IndexedArrayItem<TContent>[] ToIndexedArray<TContent>(this IEnumerable<TContent> source)
where TContent : class, IPublishedContent
{
return new PublishedContentSet<T>(source);
}
/// <summary>
/// Returns the ordered content enumerable as an ordered content set.
/// </summary>
/// <param name="source">The ordered content enumerable.</param>
/// <returns>A ordered content set wrapping the ordered content enumerable.</returns>
public static PublishedContentOrderedSet<T> ToContentSet<T>(this IOrderedEnumerable<T> source)
where T : class, IPublishedContent
{
return new PublishedContentOrderedSet<T>(source);
var set = source.Select((content, index) => new IndexedArrayItem<TContent>(content, index)).ToArray();
foreach (var setItem in set) setItem.TotalCount = set.Length;
return set;
}
#endregion
@@ -552,28 +538,6 @@ namespace Umbraco.Web
#endregion
#region ContentSet
public static int Position(this IPublishedContent content)
{
return content.GetIndex();
}
public static int Index(this IPublishedContent content)
{
return content.GetIndex();
}
private static int GetIndex(this IPublishedContent content, IEnumerable<IPublishedContent> set)
{
var index = set.FindIndex(n => n.Id == content.Id);
if (index < 0)
throw new IndexOutOfRangeException("Could not find content in the content set.");
return index;
}
#endregion
#region IsSomething: misc.
/// <summary>
@@ -646,160 +610,6 @@ namespace Umbraco.Web
#endregion
#region IsSomething: position in set
public static bool IsFirst(this IPublishedContent content)
{
return content.GetIndex() == 0;
}
public static HtmlString IsFirst(this IPublishedContent content, string valueIfTrue)
{
return content.IsFirst(valueIfTrue, string.Empty);
}
public static HtmlString IsFirst(this IPublishedContent content, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(content.IsFirst() ? valueIfTrue : valueIfFalse);
}
public static bool IsNotFirst(this IPublishedContent content)
{
return content.IsFirst() == false;
}
public static HtmlString IsNotFirst(this IPublishedContent content, string valueIfTrue)
{
return content.IsNotFirst(valueIfTrue, string.Empty);
}
public static HtmlString IsNotFirst(this IPublishedContent content, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(content.IsNotFirst() ? valueIfTrue : valueIfFalse);
}
public static bool IsPosition(this IPublishedContent content, int index)
{
return content.GetIndex() == index;
}
public static HtmlString IsPosition(this IPublishedContent content, int index, string valueIfTrue)
{
return content.IsPosition(index, valueIfTrue, string.Empty);
}
public static HtmlString IsPosition(this IPublishedContent content, int index, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(content.IsPosition(index) ? valueIfTrue : valueIfFalse);
}
public static bool IsModZero(this IPublishedContent content, int modulus)
{
return content.GetIndex() % modulus == 0;
}
public static HtmlString IsModZero(this IPublishedContent content, int modulus, string valueIfTrue)
{
return content.IsModZero(modulus, valueIfTrue, string.Empty);
}
public static HtmlString IsModZero(this IPublishedContent content, int modulus, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(content.IsModZero(modulus) ? valueIfTrue : valueIfFalse);
}
public static bool IsNotModZero(this IPublishedContent content, int modulus)
{
return content.IsModZero(modulus) == false;
}
public static HtmlString IsNotModZero(this IPublishedContent content, int modulus, string valueIfTrue)
{
return content.IsNotModZero(modulus, valueIfTrue, string.Empty);
}
public static HtmlString IsNotModZero(this IPublishedContent content, int modulus, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(content.IsNotModZero(modulus) ? valueIfTrue : valueIfFalse);
}
public static bool IsNotPosition(this IPublishedContent content, int index)
{
return content.IsPosition(index) == false;
}
public static HtmlString IsNotPosition(this IPublishedContent content, int index, string valueIfTrue)
{
return content.IsNotPosition(index, valueIfTrue, string.Empty);
}
public static HtmlString IsNotPosition(this IPublishedContent content, int index, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(content.IsNotPosition(index) ? valueIfTrue : valueIfFalse);
}
public static bool IsLast(this IPublishedContent content)
{
return content.GetIndex() == content.ContentSet.Count() - 1;
}
public static HtmlString IsLast(this IPublishedContent content, string valueIfTrue)
{
return content.IsLast(valueIfTrue, string.Empty);
}
public static HtmlString IsLast(this IPublishedContent content, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(content.IsLast() ? valueIfTrue : valueIfFalse);
}
public static bool IsNotLast(this IPublishedContent content)
{
return content.IsLast() == false;
}
public static HtmlString IsNotLast(this IPublishedContent content, string valueIfTrue)
{
return content.IsNotLast(valueIfTrue, string.Empty);
}
public static HtmlString IsNotLast(this IPublishedContent content, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(content.IsNotLast() ? valueIfTrue : valueIfFalse);
}
public static bool IsEven(this IPublishedContent content)
{
return content.GetIndex() % 2 == 0;
}
public static HtmlString IsEven(this IPublishedContent content, string valueIfTrue)
{
return content.IsEven(valueIfTrue, string.Empty);
}
public static HtmlString IsEven(this IPublishedContent content, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(content.IsEven() ? valueIfTrue : valueIfFalse);
}
public static bool IsOdd(this IPublishedContent content)
{
return content.GetIndex() % 2 == 1;
}
public static HtmlString IsOdd(this IPublishedContent content, string valueIfTrue)
{
return content.IsOdd(valueIfTrue, string.Empty);
}
public static HtmlString IsOdd(this IPublishedContent content, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(content.IsOdd() ? valueIfTrue : valueIfFalse);
}
#endregion
#region IsSomething: equality
public static bool IsEqual(this IPublishedContent content, IPublishedContent other)
@@ -1440,250 +1250,6 @@ namespace Umbraco.Web
return content.Descendant(contentTypeAlias);
}
// next pseudo-axe ~ following within the content set
// bogus, kept for backward compatibility but we should get rid of it
public static IPublishedContent Next(this IPublishedContent content)
{
return content.ContentSet.ElementAtOrDefault(content.GetIndex() + 1);
}
public static IPublishedContent Next(this IPublishedContent current, Func<IPublishedContent, bool> func) {
IPublishedContent next = current.Next();
while (next != null) {
if (func(next)) return next;
next = next.Next();
}
return null;
}
public static IPublishedContent Next(this IPublishedContent content, int number)
{
if (number < 0)
throw new ArgumentOutOfRangeException("number", "Must be greater than, or equal to, zero.");
return number == 0 ? content : content.ContentSet.ElementAtOrDefault(content.GetIndex() + number);
}
public static IPublishedContent Next(this IPublishedContent content, string contentTypeAlias)
{
return content.Next(contentTypeAlias, false);
}
public static IPublishedContent Next(this IPublishedContent content, string contentTypeAlias, bool wrap)
{
return content.Next(content.ContentSet, x => x.DocumentTypeAlias.InvariantEquals(contentTypeAlias), wrap);
}
public static T Next<T>(this IPublishedContent content)
where T : class, IPublishedContent
{
return content.Next<T>(false);
}
public static T Next<T>(this IPublishedContent content, bool wrap)
where T : class, IPublishedContent
{
return content.Next(content.ContentSet, x => x is T, wrap) as T;
}
static IPublishedContent Next(this IPublishedContent content, IEnumerable<IPublishedContent> axis, Func<IPublishedContent, bool> predicate, bool wrap)
{
var b4 = true;
IPublishedContent wrapped = null;
foreach (var c in axis)
{
if (b4)
{
if (c.Id == content.Id)
b4 = false;
else if (wrap && wrapped == null && predicate(c))
wrapped = c;
continue;
}
if (predicate(c))
return c;
}
return wrapped;
}
// previous pseudo-axe ~ preceding within the content set
// bogus, kept for backward compatibility but we should get rid of it
public static IPublishedContent Previous(this IPublishedContent content)
{
return content.ContentSet.ElementAtOrDefault(content.GetIndex() - 1);
}
public static IPublishedContent Previous(this IPublishedContent current, Func<IPublishedContent, bool> func) {
IPublishedContent prev = current.Previous();
while (prev != null) {
if (func(prev)) return prev;
prev = prev.Previous();
}
return null;
}
public static IPublishedContent Previous(this IPublishedContent content, int number)
{
if (number < 0)
throw new ArgumentOutOfRangeException("number", "Must be greater than, or equal to, zero.");
return number == 0 ? content : content.ContentSet.ElementAtOrDefault(content.GetIndex() - number);
}
public static IPublishedContent Previous(this IPublishedContent content, string contentTypeAlias)
{
return content.Previous(contentTypeAlias, false);
}
public static IPublishedContent Previous(this IPublishedContent content, string contentTypeAlias, bool wrap)
{
return content.Next(content.ContentSet.Reverse(), x => x.DocumentTypeAlias.InvariantEquals(contentTypeAlias), wrap);
}
public static T Previous<T>(this IPublishedContent content)
where T : class, IPublishedContent
{
return content.Previous<T>(false);
}
public static T Previous<T>(this IPublishedContent content, bool wrap)
where T : class, IPublishedContent
{
return content.Next(content.ContentSet.Reverse(), x => x is T, wrap) as T;
}
//
[Obsolete("Obsolete, use FollowingSibling or PrecedingSibling instead.")]
public static IPublishedContent Sibling(this IPublishedContent content, int number)
{
if (number < 0)
throw new ArgumentOutOfRangeException("number", "Must be greater than, or equal to, zero.");
number += 1; // legacy is zero-based
return content.FollowingSibling(number);
}
// contentTypeAlias is case-insensitive
[Obsolete("Obsolete, use FollowingSibling or PrecedingSibling instead.")]
public static IPublishedContent Sibling(this IPublishedContent content, string contentTypeAlias)
{
// note: the original implementation seems to loop on all siblings
// ie if it reaches the end of the set, it starts again at the beginning.
// so here we wrap, although it's not consistent... but anyway those
// methods should be obsoleted.
return content.FollowingSibling(contentTypeAlias, true);
}
// following-sibling, preceding-sibling axes
public static IPublishedContent FollowingSibling(this IPublishedContent content)
{
return content.Siblings().ElementAtOrDefault(content.GetIndex(content.Siblings()) + 1);
}
public static IPublishedContent FollowingSibling(this IPublishedContent content, int number)
{
if (number < 0)
throw new ArgumentOutOfRangeException("number", "Must be greater than, or equal to, zero.");
return number == 0 ? content : content.Siblings().ElementAtOrDefault(content.GetIndex(content.Siblings()) + number);
}
// contentTypeAlias is case-insensitive
public static IPublishedContent FollowingSibling(this IPublishedContent content, string contentTypeAlias)
{
return content.FollowingSibling(contentTypeAlias, false);
}
// contentTypeAlias is case-insensitive
// note: not sure that one makes a lot of sense but it is here for backward compatibility
public static IPublishedContent FollowingSibling(this IPublishedContent content, string contentTypeAlias, bool wrap)
{
return content.Next(content.Siblings(), x => x.DocumentTypeAlias.InvariantEquals(contentTypeAlias), wrap);
}
public static T FollowingSibling<T>(this IPublishedContent content)
where T : class, IPublishedContent
{
return content.FollowingSibling<T>(false);
}
public static T FollowingSibling<T>(this IPublishedContent content, bool wrap)
where T : class, IPublishedContent
{
return content.Next(content.Siblings(), x => x is T, wrap) as T;
}
public static IPublishedContent PrecedingSibling(this IPublishedContent content)
{
return content.Siblings().ElementAtOrDefault(content.GetIndex(content.Siblings()) - 1);
}
public static IPublishedContent PrecedingSibling(this IPublishedContent content, int number)
{
if (number < 0)
throw new ArgumentOutOfRangeException("number", "Must be greater than, or equal to, zero.");
return number == 0 ? content : content.Siblings().ElementAtOrDefault(content.GetIndex(content.Siblings()) - number);
}
// contentTypeAlias is case-insensitive
public static IPublishedContent PrecedingSibling(this IPublishedContent content, string contentTypeAlias)
{
return content.PrecedingSibling(contentTypeAlias, false);
}
// contentTypeAlias is case-insensitive
// note: not sure that one makes a lot of sense but it is here for backward compatibility
public static IPublishedContent PrecedingSibling(this IPublishedContent content, string contentTypeAlias, bool wrap)
{
return content.Next(content.Siblings().Reverse(), x => x.DocumentTypeAlias.InvariantEquals(contentTypeAlias), wrap);
}
public static T PrecedingSibling<T>(this IPublishedContent content)
where T : class, IPublishedContent
{
return content.PrecedingSibling<T>(false);
}
public static T PrecedingSibling<T>(this IPublishedContent content, bool wrap)
where T : class, IPublishedContent
{
return content.Next(content.Siblings().Reverse(), x => x is T, wrap) as T;
}
// following, preceding axes - NOT IMPLEMENTED
// utilities
public static IEnumerable<IPublishedContent> Siblings(this IPublishedContent content)
{
// content.Parent, content.Children and cache.GetAtRoot() should be fast enough,
// or cached by the content cache, so that we don't have to implement cache here.
// returns the true tree siblings, even if the content is in a set
// get the root docs if parent is null
// note: I don't like having to refer to the "current" content cache here, but
// what else? would need root content to have a special, non-null but hidden,
// parent...
var siblings = content.Parent == null
? content.ItemType == PublishedItemType.Media ? UmbracoContext.Current.MediaCache.GetAtRoot() : UmbracoContext.Current.ContentCache.GetAtRoot()
: content.Parent.Children;
// make sure we run it once
return siblings.ToArray();
}
public static IEnumerable<T> Siblings<T>(this IPublishedContent content)
where T : class, IPublishedContent
{
return content.Siblings().OfType<T>();
}
#endregion
#region Axes: parent