This commit is contained in:
Sebastiaan Janssen
2013-02-21 08:52:48 -01:00
5 changed files with 881 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

@@ -5,6 +5,18 @@
<appender-ref ref="ConsoleAppender" />
</root>
<logger name="Umbraco.Core.PluginManager">
<level value="WARN" />
</logger>
<logger name="Umbraco.Core.Persistence.Database">
<level value="WARN" />
</logger>
<logger name="Umbraco.Core.Persistence.Migrations.Initial.BaseDataCreation">
<level value="WARN" />
</logger>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
<target value="Console.Out" />
<layout type="log4net.Layout.PatternLayout">

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
}
}