Merge
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -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();
|
||||
|
||||
@@ -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) =>
|
||||
{
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user