U4-6674 - Kill ToContentSet, becomes ToIndexedArray
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
172
src/Umbraco.Core/Models/PublishedContent/IndexedArrayItem.cs
Normal file
172
src/Umbraco.Core/Models/PublishedContent/IndexedArrayItem.cs
Normal file
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user