Fixed #U4-814 and got all possible unit tests that were not working for DynamicNode but were working for

DynamicPublishedContent working. And fixed up the DynamicPublishedContent unit tests as these weren't working at all...
but seemed to say they did on the build server. strange.
This commit is contained in:
Shannon Deminick
2013-02-21 05:44:44 +06:00
parent 5b0a8c0668
commit f2d105d8b9
4 changed files with 869 additions and 813 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -54,6 +54,27 @@ namespace Umbraco.Tests.PublishedContent
}
[Test]
[Ignore("This test will never work unless DynamicNode is refactored a lot in order to get a list of root nodes since root nodes don't have a parent to look up")]
public override void Is_First_Root_Nodes()
{
base.Is_First_Root_Nodes();
}
[Test]
[Ignore("This test will never work unless DynamicNode is refactored a lot in order to get a list of root nodes since root nodes don't have a parent to look up")]
public override void Is_Not_First_Root_Nodes()
{
base.Is_Not_First_Root_Nodes();
}
[Test]
[Ignore("This test will never work unless DynamicNode is refactored a lot in order to get a list of root nodes since root nodes don't have a parent to look up")]
public override void Is_Position_Root_Nodes()
{
base.Is_Position_Root_Nodes();
}
public override void TearDown()
{
base.TearDown();

View File

@@ -1,7 +1,9 @@
using System;
using System.IO;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
using Umbraco.Web;
@@ -24,6 +26,8 @@ namespace Umbraco.Tests.PublishedContent
typeof(YesNoPropertyEditorValueConverter)
});
UmbracoSettings.SettingsFilePath = Core.IO.IOHelper.MapPath(Core.IO.SystemDirectories.Config + Path.DirectorySeparatorChar, false);
//need to specify a custom callback for unit tests
PublishedContentHelper.GetDataTypeCallback = (docTypeAlias, propertyAlias) =>
{

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
@@ -30,11 +31,11 @@ namespace umbraco.MacroEngines
{
public class DynamicNode : DynamicObject, INode
{
/// <summary>
/// This callback is used only so we can set it dynamically for use in unit tests
/// </summary>
internal static Func<string, string, Guid> GetDataTypeCallback = (docTypeAlias, propertyAlias) =>
ContentType.GetDataType(docTypeAlias, propertyAlias);
/// <summary>
/// This callback is used only so we can set it dynamically for use in unit tests
/// </summary>
internal static Func<string, string, Guid> GetDataTypeCallback = (docTypeAlias, propertyAlias) =>
ContentType.GetDataType(docTypeAlias, propertyAlias);
#region consts
// these are private readonlys as const can't be Guids
@@ -45,6 +46,9 @@ namespace umbraco.MacroEngines
//private readonly Guid DATATYPE_INTEGER_GUID = new Guid("1413afcb-d19a-4173-8e9a-68288d2a73b8");
#endregion
private DynamicNodeList _cachedChildren;
private readonly ConcurrentDictionary<string, object> _cachedMemberOutput = new ConcurrentDictionary<string, object>();
internal readonly DynamicBackingItem n;
public DynamicNodeList ownerList;
@@ -154,13 +158,20 @@ namespace umbraco.MacroEngines
{
get
{
List<DynamicBackingItem> children = n.ChildrenAsList;
//testing
if (children.Count == 0 && n.Id == 0)
if (_cachedChildren == null)
{
return new DynamicNodeList(new List<DynamicBackingItem> { this.n });
List<DynamicBackingItem> children = n.ChildrenAsList;
//testing
if (children.Count == 0 && n.Id == 0)
{
_cachedChildren = new DynamicNodeList(new List<DynamicBackingItem> { this.n });
}
else
{
_cachedChildren = new DynamicNodeList(n.ChildrenAsList);
}
}
return new DynamicNodeList(n.ChildrenAsList);
return _cachedChildren;
}
}
public DynamicNodeList XPath(string xPath)
@@ -234,12 +245,12 @@ namespace umbraco.MacroEngines
throw new NullReferenceException("DynamicNode wasn't initialized with an underlying NodeFactory.Node");
}
}
public DynamicNodeList Search(string term, bool useWildCards = true, string searchProvider = null)
{
var searcher = Examine.ExamineManager.Instance.DefaultSearchProvider;
if(!string.IsNullOrEmpty(searchProvider))
if (!string.IsNullOrEmpty(searchProvider))
searcher = Examine.ExamineManager.Instance.SearchProviderCollection[searchProvider];
var t = term.Escape().Value;
@@ -279,13 +290,13 @@ namespace umbraco.MacroEngines
var s = Examine.ExamineManager.Instance.DefaultSearchProvider;
if (searchProvider != null)
s = searchProvider;
var results = s.Search(criteria);
return ExamineSearchUtill.ConvertSearchResultToDynamicNode(results);
}
public bool HasProperty(string name)
{
@@ -406,125 +417,99 @@ namespace umbraco.MacroEngines
}
return result;
}
private List<string> GetAncestorOrSelfNodeTypeAlias(DynamicBackingItem node)
{
List<string> list = new List<string>();
if (node != null)
{
if (node.Type == DynamicBackingItemType.Content)
{
//find the doctype node, so we can walk it's parent's tree- not the working.parent content tree
CMSNode working = ContentType.GetByAlias(node.NodeTypeAlias);
while (working != null)
{
//NOTE: I'm not sure if anyone has ever tested this but if you get working.Parent it will return a CMSNode and
// it will never be castable to a 'ContentType' object
// pretty sure the only reason why this method works for the one place that it is used is that it returns
// the current node's alias which is all that is actually requried, this is just added overhead for no
// reason
if ((working as ContentType) != null)
{
list.Add((working as ContentType).Alias);
}
private static Dictionary<System.Tuple<Guid, int>, Type> _razorDataTypeModelTypes = null;
private static readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim();
internal static Dictionary<System.Tuple<Guid, int>, Type> RazorDataTypeModelTypes
{
get
{
using (var l = new UpgradeableReadLock(_locker))
{
if (_razorDataTypeModelTypes == null)
{
l.UpgradeToWriteLock();
var foundTypes = new Dictionary<System.Tuple<Guid, int>, Type>();
try
{
working = working.Parent;
PluginManager.Current.ResolveRazorDataTypeModels()
.ToList()
.ConvertAll(type =>
{
var razorDataTypeModelAttributes = type.GetCustomAttributes<RazorDataTypeModel>(true);
return razorDataTypeModelAttributes.ToList().ConvertAll(razorDataTypeModelAttribute =>
{
var g = razorDataTypeModelAttribute.DataTypeEditorId;
var priority = razorDataTypeModelAttribute.Priority;
return new KeyValuePair<System.Tuple<Guid, int>, Type>(new System.Tuple<Guid, int>(g, priority), type);
});
})
.SelectMany(item => item)
.ToList()
.ForEach(item =>
{
System.Tuple<Guid, int> key = item.Key;
if (!foundTypes.ContainsKey(key))
{
foundTypes.Add(key, item.Value);
}
});
//there is no error, so set the collection
_razorDataTypeModelTypes = foundTypes;
}
catch (ArgumentException)
catch (Exception ex)
{
break;
LogHelper.Warn<DynamicNode>("Exception occurred while populating cache, will keep RazorDataTypeModelTypes to null so that this error remains visible and you don't end up with an empty cache with silent failure."
+ string.Format("The exception was {0} and the message was {1}. {2}", ex.GetType().FullName, ex.Message, ex.StackTrace));
}
}
}
else
{
return null;
return _razorDataTypeModelTypes;
}
}
return list;
}
private static Dictionary<System.Tuple<Guid, int>, Type> _razorDataTypeModelTypes = null;
private static readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim();
internal static Dictionary<System.Tuple<Guid, int>, Type> RazorDataTypeModelTypes
{
get
{
using (var l = new UpgradeableReadLock(_locker))
{
if (_razorDataTypeModelTypes == null)
{
l.UpgradeToWriteLock();
var foundTypes = new Dictionary<System.Tuple<Guid, int>, Type>();
try
{
PluginManager.Current.ResolveRazorDataTypeModels()
.ToList()
.ConvertAll(type =>
{
var razorDataTypeModelAttributes = type.GetCustomAttributes<RazorDataTypeModel>(true);
return razorDataTypeModelAttributes.ToList().ConvertAll(razorDataTypeModelAttribute =>
{
var g = razorDataTypeModelAttribute.DataTypeEditorId;
var priority = razorDataTypeModelAttribute.Priority;
return new KeyValuePair<System.Tuple<Guid, int>, Type>(new System.Tuple<Guid, int>(g, priority), type);
});
})
.SelectMany(item => item)
.ToList()
.ForEach(item =>
{
System.Tuple<Guid, int> key = item.Key;
if (!foundTypes.ContainsKey(key))
{
foundTypes.Add(key, item.Value);
}
});
//NOTE: We really dont need to log this?
//var i = 1;
//foreach (var item in foundTypes)
//{
// HttpContext.Current.Trace.Write(string.Format("{0}/{1}: {2}@{4} => {3}", i, foundTypes.Count, item.Key.Item1, item.Value.FullName, item.Key.Item2));
// i++;
//}
//there is no error, so set the collection
_razorDataTypeModelTypes = foundTypes;
}
catch (Exception ex)
{
LogHelper.Warn<DynamicNode>("Exception occurred while populating cache, will keep RazorDataTypeModelTypes to null so that this error remains visible and you don't end up with an empty cache with silent failure."
+ string.Format("The exception was {0} and the message was {1}. {2}", ex.GetType().FullName, ex.Message, ex.StackTrace));
}
}
return _razorDataTypeModelTypes;
}
}
}
private static Guid GetDataType(string docTypeAlias, string propertyAlias)
{
return GetDataTypeCallback(docTypeAlias, propertyAlias);
}
private static Guid GetDataType(string docTypeAlias, string propertyAlias)
{
return GetDataTypeCallback(docTypeAlias, propertyAlias);
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
var name = binder.Name;
result = null; //this will never be returned
if (name == "ChildrenAsList" || name == "Children")
//check the cache first!
if (_cachedMemberOutput.TryGetValue(name, out result))
{
result = GetChildrenAsList;
return true;
}
result = null; //this will never be returned
if (name.InvariantEquals("ChildrenAsList") || name.InvariantEquals("Children"))
{
result = GetChildrenAsList;
//cache the result so we don't have to re-process the whole thing
_cachedMemberOutput.TryAdd(name, result);
return true;
}
if (binder.Name.InvariantEquals("parentId"))
{
var parent = n.Parent;
if (parent == null)
{
throw new InvalidOperationException(string.Format("The node {0} does not have a parent", Id));
}
result = parent.Id;
_cachedMemberOutput.TryAdd(name, result);
return true;
}
bool propertyExists = false;
if (n != null)
{
@@ -554,8 +539,8 @@ namespace umbraco.MacroEngines
//contextAlias is the node which the property data was returned from
//Guid dataType = ContentType.GetDataType(data.ContextAlias, data.Alias);
var dataType = GetDataType(data.ContextAlias, data.Alias);
var dataType = GetDataType(data.ContextAlias, data.Alias);
var staticMapping = UmbracoSettings.RazorDataTypeModelStaticMapping.FirstOrDefault(mapping =>
{
return mapping.Applies(dataType, data.ContextAlias, data.Alias);
@@ -570,19 +555,21 @@ namespace umbraco.MacroEngines
if (TryCreateInstanceRazorDataTypeModel(dataType, dataTypeType, data.Value, out instance))
{
result = instance;
//cache the result so we don't have to re-process the whole thing
_cachedMemberOutput.TryAdd(name, result);
return true;
}
else
{
LogHelper.Warn<DynamicNode>(string.Format("Failed to create the instance of the model binder"));
LogHelper.Warn<DynamicNode>(string.Format("Failed to create the instance of the model binder"));
}
}
else
{
LogHelper.Warn<DynamicNode>(string.Format("staticMapping type name {0} came back as null from Type.GetType; check the casing, assembly presence, assembly framework version, namespace", staticMapping.TypeName));
LogHelper.Warn<DynamicNode>(string.Format("staticMapping type name {0} came back as null from Type.GetType; check the casing, assembly presence, assembly framework version, namespace", staticMapping.TypeName));
}
}
if (RazorDataTypeModelTypes != null && RazorDataTypeModelTypes.Any(model => model.Key.Item1 == dataType) && dataType != Guid.Empty)
{
var razorDataTypeModelDefinition = RazorDataTypeModelTypes.Where(model => model.Key.Item1 == dataType).OrderByDescending(model => model.Key.Item2).FirstOrDefault();
@@ -593,35 +580,26 @@ namespace umbraco.MacroEngines
if (TryCreateInstanceRazorDataTypeModel(dataType, dataTypeType, data.Value, out instance))
{
result = instance;
//cache the result so we don't have to re-process the whole thing
_cachedMemberOutput.TryAdd(name, result);
return true;
}
else
{
LogHelper.Warn<DynamicNode>(string.Format("Failed to create the instance of the model binder"));
LogHelper.Warn<DynamicNode>(string.Format("Failed to create the instance of the model binder"));
}
}
else
{
LogHelper.Warn<DynamicNode>(string.Format("Could not get the dataTypeType for the RazorDataTypeModel"));
LogHelper.Warn<DynamicNode>(string.Format("Could not get the dataTypeType for the RazorDataTypeModel"));
}
}
else
{
//NOTE: Do we really want to log this? I'm not sure.
//if (RazorDataTypeModelTypes == null)
//{
// HttpContext.Current.Trace.Write(string.Format("RazorDataTypeModelTypes is null, probably an exception while building the cache, falling back to ConvertPropertyValueByDataType", dataType));
//}
//else
//{
// HttpContext.Current.Trace.Write(string.Format("GUID {0} does not have a DataTypeModel, falling back to ConvertPropertyValueByDataType", dataType));
//}
}
//convert the string value to a known type
return ConvertPropertyValueByDataType(ref result, name, dataType);
var returnVal = ConvertPropertyValueByDataType(ref result, name, dataType);
//cache the result so we don't have to re-process the whole thing
_cachedMemberOutput.TryAdd(name, result);
return returnVal;
}
//check if the alias is that of a child type
@@ -629,39 +607,30 @@ namespace umbraco.MacroEngines
var typeChildren = n.ChildrenAsList;
if (typeChildren != null)
{
var filteredTypeChildren = typeChildren.Where(x =>
{
List<string> ancestorAliases = GetAncestorOrSelfNodeTypeAlias(x);
if (ancestorAliases == null)
{
return false;
}
return ancestorAliases.Any(alias => alias == name || MakePluralName(alias) == name);
});
var filteredTypeChildren = typeChildren
.Where(x => x.NodeTypeAlias.InvariantEquals(name) || x.NodeTypeAlias.MakePluralName().InvariantEquals(binder.Name))
.ToArray();
if (filteredTypeChildren.Any())
{
result = new DynamicNodeList(filteredTypeChildren);
//cache the result so we don't have to re-process the whole thing
_cachedMemberOutput.TryAdd(name, result);
return true;
}
}
try
//lookup the property using reflection
result = GetReflectedProperty(binder.Name);
if (result != null)
{
result = n.GetType().InvokeMember(binder.Name,
System.Reflection.BindingFlags.GetProperty |
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.Public,
null,
n,
null);
_cachedMemberOutput.TryAdd(name, result);
return true;
}
catch
{
//result = null;
//return false;
}
}
//if property access, type lookup and member invoke all failed
@@ -679,6 +648,42 @@ namespace umbraco.MacroEngines
}
return true;
}
private object GetReflectedProperty(string alias)
{
Func<string, Attempt<object>> getMember =
memberAlias =>
{
try
{
return new Attempt<object>(true,
n.GetType().InvokeMember(memberAlias,
System.Reflection.BindingFlags.GetProperty |
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.Public,
null,
n,
null));
}
catch (MissingMethodException ex)
{
return new Attempt<object>(ex);
}
};
//try with the current casing
var attempt = getMember(alias);
if (!attempt.Success)
{
//if we cannot get with the current alias, try changing it's case
attempt = alias[0].IsUpperCase()
? getMember(alias.ConvertCase(StringAliasCaseType.CamelCase))
: getMember(alias.ConvertCase(StringAliasCaseType.PascalCase));
}
return attempt.Success ? attempt.Result : null;
}
private bool TryCreateInstanceRazorDataTypeModel(Guid dataType, Type dataTypeType, string value, out object result)
{
IRazorDataTypeModel razorDataTypeModel = Activator.CreateInstance(dataTypeType, false) as IRazorDataTypeModel;
@@ -689,22 +694,22 @@ namespace umbraco.MacroEngines
{
if (instance == null)
{
LogHelper.Warn<DynamicNode>("razorDataTypeModel successfully instantiated but returned null for instance");
LogHelper.Warn<DynamicNode>("razorDataTypeModel successfully instantiated but returned null for instance");
}
result = instance;
result = instance;
return true;
}
else
{
if (instance == null)
{
LogHelper.Warn<DynamicNode>("razorDataTypeModel successfully instantiated but returned null for instance");
LogHelper.Warn<DynamicNode>("razorDataTypeModel successfully instantiated but returned null for instance");
}
}
}
else
{
LogHelper.Warn<DynamicNode>(string.Format("DataTypeModel {0} failed to instantiate, perhaps it is lacking a parameterless constructor or doesn't implement IRazorDataTypeModel?", dataTypeType.FullName));
LogHelper.Warn<DynamicNode>(string.Format("DataTypeModel {0} failed to instantiate, perhaps it is lacking a parameterless constructor or doesn't implement IRazorDataTypeModel?", dataTypeType.FullName));
}
result = null;
return false;
@@ -1329,15 +1334,15 @@ namespace umbraco.MacroEngines
{
get
{
return GetChildrenAsList;
//if (n == null) return null; return n.ChildrenAsList;
return GetChildrenAsList;
//if (n == null) return null; return n.ChildrenAsList;
}
}
public DynamicNodeList Children
{
get { return ChildrenAsList; }
}
public DynamicNodeList Children
{
get { return ChildrenAsList; }
}
public IProperty GetProperty(string alias)
{
@@ -1368,13 +1373,25 @@ namespace umbraco.MacroEngines
}
public string GetPropertyValue(string alias, string fallback)
{
var prop = GetProperty(alias);
if (prop != null) return prop.Value;
return fallback;
string prop;
if (alias.StartsWith("@"))
{
var p = GetReflectedProperty(alias.TrimStart('@'));
prop = p == null ? null : p.ToString();
}
else
{
var p = GetProperty(alias);
prop = p != null ? p.Value : null;
}
return !prop.IsNullOrWhiteSpace() ? prop : fallback;
}
public string GetPropertyValue(string alias, bool recursive)
{
return GetPropertyValue(alias, recursive, null);
var p = alias.StartsWith("@")
? GetReflectedProperty(alias.TrimStart('@'))
: GetPropertyValue(alias, recursive, null);
return (string)p;
}
public string GetPropertyValue(string alias, bool recursive, string fallback)
{
@@ -1433,14 +1450,24 @@ namespace umbraco.MacroEngines
{
return this.Index();
}
public int Index()
/// <summary>
/// Checks if the owner list is null and attempts to create it if there is a parent.
/// </summary>
/// <returns>Successful if the owners list is not null, false if the owners list could not be created and remains null</returns>
private bool EnsureOwnersList()
{
if (this.ownerList == null && this.Parent != null)
{
var list = this.Parent.ChildrenAsList.Select(n => new DynamicNode(n));
this.ownerList = new DynamicNodeList(list);
}
if (this.ownerList != null)
return this.ownerList != null;
}
public int Index()
{
if (EnsureOwnersList())
{
List<DynamicNode> container = this.ownerList.Items.ToList();
int currentIndex = container.FindIndex(n => n.Id == this.Id);
@@ -1448,16 +1475,11 @@ namespace umbraco.MacroEngines
{
return currentIndex;
}
else
{
throw new IndexOutOfRangeException(string.Format("Node {0} belongs to a DynamicNodeList but could not retrieve the index for it's position in the list", this.Id));
}
}
else
{
throw new ArgumentNullException(string.Format("Node {0} has been orphaned and doesn't belong to a DynamicNodeList", this.Id));
throw new IndexOutOfRangeException(string.Format("Node {0} belongs to a DynamicNodeList but could not retrieve the index for it's position in the list", this.Id));
}
throw new ArgumentNullException(string.Format("Node {0} has been orphaned and doesn't belong to a DynamicNodeList", this.Id));
}
public bool IsFirst()
{
return IsHelper(n => n.Index() == 0);
@@ -1484,7 +1506,7 @@ namespace umbraco.MacroEngines
}
public bool IsPosition(int index)
{
if (this.ownerList == null)
if (!EnsureOwnersList())
{
return false;
}
@@ -1492,7 +1514,7 @@ namespace umbraco.MacroEngines
}
public HtmlString IsPosition(int index, string valueIfTrue)
{
if (this.ownerList == null)
if (!EnsureOwnersList())
{
return new HtmlString(string.Empty);
}
@@ -1500,7 +1522,7 @@ namespace umbraco.MacroEngines
}
public HtmlString IsPosition(int index, string valueIfTrue, string valueIfFalse)
{
if (this.ownerList == null)
if (!EnsureOwnersList())
{
return new HtmlString(valueIfFalse);
}
@@ -1508,7 +1530,7 @@ namespace umbraco.MacroEngines
}
public bool IsModZero(int modulus)
{
if (this.ownerList == null)
if (!EnsureOwnersList())
{
return false;
}
@@ -1516,7 +1538,7 @@ namespace umbraco.MacroEngines
}
public HtmlString IsModZero(int modulus, string valueIfTrue)
{
if (this.ownerList == null)
if (!EnsureOwnersList())
{
return new HtmlString(string.Empty);
}
@@ -1524,7 +1546,7 @@ namespace umbraco.MacroEngines
}
public HtmlString IsModZero(int modulus, string valueIfTrue, string valueIfFalse)
{
if (this.ownerList == null)
if (!EnsureOwnersList())
{
return new HtmlString(valueIfFalse);
}
@@ -1533,7 +1555,7 @@ namespace umbraco.MacroEngines
public bool IsNotModZero(int modulus)
{
if (this.ownerList == null)
if (!EnsureOwnersList())
{
return false;
}
@@ -1541,7 +1563,7 @@ namespace umbraco.MacroEngines
}
public HtmlString IsNotModZero(int modulus, string valueIfTrue)
{
if (this.ownerList == null)
if (!EnsureOwnersList())
{
return new HtmlString(string.Empty);
}
@@ -1549,7 +1571,7 @@ namespace umbraco.MacroEngines
}
public HtmlString IsNotModZero(int modulus, string valueIfTrue, string valueIfFalse)
{
if (this.ownerList == null)
if (!EnsureOwnersList())
{
return new HtmlString(valueIfFalse);
}
@@ -1557,7 +1579,7 @@ namespace umbraco.MacroEngines
}
public bool IsNotPosition(int index)
{
if (this.ownerList == null)
if (!EnsureOwnersList())
{
return false;
}
@@ -1565,7 +1587,7 @@ namespace umbraco.MacroEngines
}
public HtmlString IsNotPosition(int index, string valueIfTrue)
{
if (this.ownerList == null)
if (!EnsureOwnersList())
{
return new HtmlString(string.Empty);
}
@@ -1573,7 +1595,7 @@ namespace umbraco.MacroEngines
}
public HtmlString IsNotPosition(int index, string valueIfTrue, string valueIfFalse)
{
if (this.ownerList == null)
if (!EnsureOwnersList())
{
return new HtmlString(valueIfFalse);
}
@@ -1581,7 +1603,7 @@ namespace umbraco.MacroEngines
}
public bool IsLast()
{
if (this.ownerList == null)
if (!EnsureOwnersList())
{
return false;
}
@@ -1590,7 +1612,7 @@ namespace umbraco.MacroEngines
}
public HtmlString IsLast(string valueIfTrue)
{
if (this.ownerList == null)
if (!EnsureOwnersList())
{
return new HtmlString(string.Empty);
}
@@ -1599,7 +1621,7 @@ namespace umbraco.MacroEngines
}
public HtmlString IsLast(string valueIfTrue, string valueIfFalse)
{
if (this.ownerList == null)
if (!EnsureOwnersList())
{
return new HtmlString(valueIfFalse);
}
@@ -1608,7 +1630,7 @@ namespace umbraco.MacroEngines
}
public bool IsNotLast()
{
if (this.ownerList == null)
if (!EnsureOwnersList())
{
return false;
}
@@ -1617,7 +1639,7 @@ namespace umbraco.MacroEngines
}
public HtmlString IsNotLast(string valueIfTrue)
{
if (this.ownerList == null)
if (!EnsureOwnersList())
{
return new HtmlString(string.Empty);
}
@@ -1626,7 +1648,7 @@ namespace umbraco.MacroEngines
}
public HtmlString IsNotLast(string valueIfTrue, string valueIfFalse)
{
if (this.ownerList == null)
if (!EnsureOwnersList())
{
return new HtmlString(valueIfFalse);
}
@@ -1779,128 +1801,128 @@ namespace umbraco.MacroEngines
return false;
}
#region Explicit INode implementation
INode INode.Parent
{
get { return Parent; }
}
#region Explicit INode implementation
INode INode.Parent
{
get { return Parent; }
}
int INode.Id
{
get { return Id; }
}
int INode.Id
{
get { return Id; }
}
int INode.template
{
get { return template; }
}
int INode.template
{
get { return template; }
}
int INode.SortOrder
{
get { return SortOrder; }
}
int INode.SortOrder
{
get { return SortOrder; }
}
string INode.Name
{
get { return Name; }
}
string INode.Name
{
get { return Name; }
}
string INode.Url
{
get { return Url; }
}
string INode.Url
{
get { return Url; }
}
string INode.UrlName
{
get { return UrlName; }
}
string INode.UrlName
{
get { return UrlName; }
}
string INode.NodeTypeAlias
{
get { return NodeTypeAlias; }
}
string INode.NodeTypeAlias
{
get { return NodeTypeAlias; }
}
string INode.WriterName
{
get { return WriterName; }
}
string INode.WriterName
{
get { return WriterName; }
}
string INode.CreatorName
{
get { return CreatorName; }
}
string INode.CreatorName
{
get { return CreatorName; }
}
int INode.WriterID
{
get { return WriterID; }
}
int INode.WriterID
{
get { return WriterID; }
}
int INode.CreatorID
{
get { return CreatorID; }
}
int INode.CreatorID
{
get { return CreatorID; }
}
string INode.Path
{
get { return Path; }
}
string INode.Path
{
get { return Path; }
}
DateTime INode.CreateDate
{
get { return CreateDate; }
}
DateTime INode.CreateDate
{
get { return CreateDate; }
}
DateTime INode.UpdateDate
{
get { return UpdateDate; }
}
DateTime INode.UpdateDate
{
get { return UpdateDate; }
}
Guid INode.Version
{
get { return Version; }
}
Guid INode.Version
{
get { return Version; }
}
string INode.NiceUrl
{
get { return NiceUrl; }
}
string INode.NiceUrl
{
get { return NiceUrl; }
}
int INode.Level
{
get { return Level; }
}
int INode.Level
{
get { return Level; }
}
List<IProperty> INode.PropertiesAsList
{
get { return PropertiesAsList; }
}
List<IProperty> INode.PropertiesAsList
{
get { return PropertiesAsList; }
}
List<INode> INode.ChildrenAsList
{
get { return new List<INode>(ChildrenAsList.Select(x => x).ToList()); }
}
List<INode> INode.ChildrenAsList
{
get { return new List<INode>(ChildrenAsList.Select(x => x).ToList()); }
}
IProperty INode.GetProperty(string Alias)
{
return GetProperty(Alias);
}
IProperty INode.GetProperty(string Alias)
{
return GetProperty(Alias);
}
IProperty INode.GetProperty(string Alias, out bool propertyExists)
{
var p = GetProperty(Alias, false);
propertyExists = p != null;
return p;
}
IProperty INode.GetProperty(string Alias, out bool propertyExists)
{
var p = GetProperty(Alias, false);
propertyExists = p != null;
return p;
}
System.Data.DataTable INode.ChildrenAsTable()
{
return ChildrenAsTable();
}
System.Data.DataTable INode.ChildrenAsTable()
{
return ChildrenAsTable();
}
System.Data.DataTable INode.ChildrenAsTable(string nodeTypeAliasFilter)
{
return ChildrenAsTable(nodeTypeAliasFilter);
}
#endregion
}
System.Data.DataTable INode.ChildrenAsTable(string nodeTypeAliasFilter)
{
return ChildrenAsTable(nodeTypeAliasFilter);
}
#endregion
}
}