Merge with 4.10.0
This commit is contained in:
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Configuration;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
@@ -197,13 +198,19 @@ namespace Umbraco.Core.Configuration
|
||||
vDir = v.PhysicalDirectory;
|
||||
}
|
||||
}
|
||||
|
||||
var doc = new XmlDocument();
|
||||
doc.Load(String.Concat(vDir, "web.config"));
|
||||
var root = doc.DocumentElement;
|
||||
var setting = doc.SelectSingleNode(String.Concat("//appSettings/add[@key='", key, "']"));
|
||||
setting.Attributes["value"].InnerText = value;
|
||||
doc.Save(String.Concat(vDir, "web.config"));
|
||||
|
||||
string fileName = String.Concat(vDir, "web.config");
|
||||
var xml = XDocument.Load(fileName);
|
||||
var appSettings = xml.Root.Descendants("appSettings").Single();
|
||||
|
||||
// Update appSetting if it exists, or else create a new appSetting for the given key and value
|
||||
var setting = appSettings.Descendants("add").Where(s => s.Attribute("key").Value == key).FirstOrDefault();
|
||||
if (setting == null)
|
||||
appSettings.Add(new XElement("add", new XAttribute("key", key), new XAttribute("value", value)));
|
||||
else
|
||||
setting.Attribute("value").Value = value;
|
||||
|
||||
xml.Save(fileName);
|
||||
ConfigurationManager.RefreshSection("appSettings");
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,11 @@ using System.Linq.Expressions;
|
||||
|
||||
namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
/// <summary>
|
||||
/// Utility class for finding extension methods on a type to execute
|
||||
/// </summary>
|
||||
internal static class ExtensionMethodFinder
|
||||
{
|
||||
|
||||
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns all extension methods found matching the definition
|
||||
/// </summary>
|
||||
@@ -22,7 +23,7 @@ namespace Umbraco.Core.Dynamics
|
||||
/// <param name="argsContainsThis"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// NOTE: This will be an intensive method to call!! Results should be cached!
|
||||
/// TODO: NOTE: This will be an intensive method to call!! Results should be cached!
|
||||
/// </remarks>
|
||||
private static IEnumerable<MethodInfo> GetAllExtensionMethods(Type thisType, string name, int argumentCount, bool argsContainsThis)
|
||||
{
|
||||
@@ -62,7 +63,8 @@ namespace Umbraco.Core.Dynamics
|
||||
|
||||
return methodsWhereArgZeroIsTargetType.Select(mt => mt.m);
|
||||
}
|
||||
private static bool MethodArgZeroHasCorrectTargetType(MethodInfo method, Type firstArgumentType, Type thisType)
|
||||
|
||||
private static bool MethodArgZeroHasCorrectTargetType(MethodInfo method, Type firstArgumentType, Type thisType)
|
||||
{
|
||||
//This is done with seperate method calls because you can't debug/watch lamdas - if you're trying to figure
|
||||
//out why the wrong method is returned, it helps to be able to see each boolean result
|
||||
@@ -112,7 +114,8 @@ namespace Umbraco.Core.Dynamics
|
||||
bool result = (thisType == firstArgumentType);
|
||||
return result;
|
||||
}
|
||||
private static Type FirstParameterType(MethodInfo m)
|
||||
|
||||
private static Type FirstParameterType(MethodInfo m)
|
||||
{
|
||||
ParameterInfo[] p = m.GetParameters();
|
||||
if (p.Any())
|
||||
@@ -122,71 +125,74 @@ namespace Umbraco.Core.Dynamics
|
||||
return null;
|
||||
}
|
||||
|
||||
private static MethodInfo DetermineMethodFromParams(IEnumerable<MethodInfo> methods, Type genericType, IEnumerable<object> args)
|
||||
{
|
||||
if (!methods.Any())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
MethodInfo methodToExecute = null;
|
||||
if (methods.Count() > 1)
|
||||
{
|
||||
//Given the args, lets get the types and compare the type sequence to try and find the correct overload
|
||||
var argTypes = args.ToList().ConvertAll(o =>
|
||||
{
|
||||
var oe = (o as Expression);
|
||||
if (oe != null)
|
||||
{
|
||||
return oe.Type.FullName;
|
||||
}
|
||||
return o.GetType().FullName;
|
||||
});
|
||||
var methodsWithArgTypes = methods.Select(method => new { method, types = method.GetParameters().Select(pi => pi.ParameterType.FullName) });
|
||||
var firstMatchingOverload = methodsWithArgTypes.FirstOrDefault(m => m.types.SequenceEqual(argTypes));
|
||||
if (firstMatchingOverload != null)
|
||||
{
|
||||
methodToExecute = firstMatchingOverload.method;
|
||||
}
|
||||
}
|
||||
|
||||
if (methodToExecute == null)
|
||||
{
|
||||
var firstMethod = methods.FirstOrDefault();
|
||||
// NH: this is to ensure that it's always the correct one being chosen when using the LINQ extension methods
|
||||
if (methods.Count() > 1)
|
||||
{
|
||||
var firstGenericMethod = methods.FirstOrDefault(x => x.IsGenericMethodDefinition);
|
||||
if (firstGenericMethod != null)
|
||||
{
|
||||
firstMethod = firstGenericMethod;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstMethod != null)
|
||||
{
|
||||
if (firstMethod.IsGenericMethodDefinition)
|
||||
{
|
||||
if (genericType != null)
|
||||
{
|
||||
methodToExecute = firstMethod.MakeGenericMethod(genericType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
methodToExecute = firstMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
return methodToExecute;
|
||||
}
|
||||
|
||||
public static MethodInfo FindExtensionMethod(Type thisType, object[] args, string name, bool argsContainsThis)
|
||||
{
|
||||
Type genericType = null;
|
||||
if (thisType.IsGenericType)
|
||||
{
|
||||
genericType = thisType.GetGenericArguments()[0];
|
||||
}
|
||||
}
|
||||
|
||||
var methods = GetAllExtensionMethods(thisType, name, args.Length, argsContainsThis)
|
||||
.ToArray();
|
||||
|
||||
if (!methods.Any())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
MethodInfo methodToExecute = null;
|
||||
if (methods.Count() > 1)
|
||||
{
|
||||
//Given the args, lets get the types and compare the type sequence to try and find the correct overload
|
||||
var argTypes = args.ToList().ConvertAll(o =>
|
||||
{
|
||||
var oe = (o as Expression);
|
||||
if (oe != null)
|
||||
{
|
||||
return oe.Type.FullName;
|
||||
}
|
||||
return o.GetType().FullName;
|
||||
});
|
||||
var methodsWithArgTypes = methods.Select(method => new {method, types = method.GetParameters().Select(pi => pi.ParameterType.FullName) });
|
||||
var firstMatchingOverload = methodsWithArgTypes.FirstOrDefault(m => m.types.SequenceEqual(argTypes));
|
||||
if (firstMatchingOverload != null)
|
||||
{
|
||||
methodToExecute = firstMatchingOverload.method;
|
||||
}
|
||||
}
|
||||
|
||||
if (methodToExecute == null)
|
||||
{
|
||||
var firstMethod = methods.FirstOrDefault();
|
||||
// NH: this is to ensure that it's always the correct one being chosen when using the LINQ extension methods
|
||||
if (methods.Count() > 1)
|
||||
{
|
||||
var firstGenericMethod = methods.FirstOrDefault(x => x.IsGenericMethodDefinition);
|
||||
if (firstGenericMethod != null)
|
||||
{
|
||||
firstMethod = firstGenericMethod;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstMethod != null)
|
||||
{
|
||||
if (firstMethod.IsGenericMethodDefinition)
|
||||
{
|
||||
if (genericType != null)
|
||||
{
|
||||
methodToExecute = firstMethod.MakeGenericMethod(genericType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
methodToExecute = firstMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
return methodToExecute;
|
||||
var methods = GetAllExtensionMethods(thisType, name, args.Length, argsContainsThis).ToArray();
|
||||
return DetermineMethodFromParams(methods, genericType, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,14 +53,19 @@ namespace Umbraco.Tests.DynamicDocument
|
||||
<creatorName><![CDATA[Custom data with same property name as the member name]]></creatorName>
|
||||
</Home>
|
||||
<Home id=""1176"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""3"" createDate=""2012-07-20T18:08:08"" updateDate=""2012-07-20T19:10:52"" nodeName=""Sub 3"" urlName=""sub-3"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1176"" isDoc="""">
|
||||
<content><![CDATA[]]></content>
|
||||
<content><![CDATA[some content]]></content>
|
||||
<blah><![CDATA[some content]]></blah>
|
||||
</Home>
|
||||
<CustomDocument id=""1177"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""4"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""custom sub 1"" urlName=""custom-sub-1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1177"" isDoc="""" />
|
||||
<CustomDocument id=""1178"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""4"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-16T14:23:35"" nodeName=""custom sub 2"" urlName=""custom-sub-2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1178"" isDoc="""" />
|
||||
</Home>
|
||||
<Home id=""1175"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""3"" createDate=""2012-07-20T18:08:01"" updateDate=""2012-07-20T18:49:32"" nodeName=""Sub 2"" urlName=""sub-2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1175"" isDoc=""""><content><![CDATA[]]></content>
|
||||
</Home>
|
||||
<CustomDocument id=""4444"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""4"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""Test"" urlName=""test-page"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,4444"" isDoc="""" />
|
||||
<CustomDocument id=""4444"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""4"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""Test"" urlName=""test-page"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,4444"" isDoc="""">
|
||||
<selectedNodes><![CDATA[1172,1176,1173]]></selectedNodes>
|
||||
<CustomDocument id=""5555"" parentID=""1046"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""0"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""Test"" urlName=""test-page"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,4444,5555"" isDoc="""">
|
||||
</CustomDocument>
|
||||
</CustomDocument>
|
||||
</Home>
|
||||
<CustomDocument id=""1172"" parentID=""-1"" level=""1"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""Test"" urlName=""test-page"" writerName=""admin"" creatorName=""admin"" path=""-1,1172"" isDoc="""" />
|
||||
</root>";
|
||||
@@ -73,6 +78,144 @@ namespace Umbraco.Tests.DynamicDocument
|
||||
/// <returns></returns>
|
||||
protected abstract dynamic GetDynamicNode(int id);
|
||||
|
||||
[Test]
|
||||
public void Single()
|
||||
{
|
||||
var doc = GetDynamicNode(4444);
|
||||
|
||||
var result = doc.Children().Single();
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(5555, result.Id);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Single_With_Query()
|
||||
{
|
||||
var doc = GetDynamicNode(1046);
|
||||
|
||||
var result = doc.Children().Single("id==1175");
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(1175, result.Id);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void First()
|
||||
{
|
||||
var doc = GetDynamicNode(1173);
|
||||
|
||||
var result = doc.Children().First();
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(1174, result.Id);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void First_With_Query()
|
||||
{
|
||||
var doc = GetDynamicNode(1173);
|
||||
|
||||
var result = doc.Children().First("blah==\"some content\"");
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(1176, result.Id);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Where_User_Property_Value()
|
||||
{
|
||||
var doc = GetDynamicNode(1173);
|
||||
|
||||
var result = (IEnumerable<dynamic>)doc.Children().Where("blah==\"some content\"");
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(1, result.Count());
|
||||
Assert.AreEqual(1176, result.Single().Id);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void String_ContainsValue_Extension_Method()
|
||||
{
|
||||
var doc = GetDynamicNode(1046);
|
||||
|
||||
var paramVals = new Dictionary<string, object> { { "searchId", 1173 } }; //this is an integer value
|
||||
var result = doc.Children()
|
||||
.Where("selectedNodes.ContainsValue(searchId)", paramVals) //call an extension method
|
||||
.FirstOrDefault();
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(4444, result.Id);
|
||||
|
||||
//don't find!
|
||||
paramVals = new Dictionary<string, object> { { "searchId", 1111777 } };
|
||||
result = doc.Children()
|
||||
.Where("selectedNodes.ContainsValue(searchId)", paramVals)
|
||||
.FirstOrDefault();
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsTrue(result.GetType() == typeof(DynamicNull) || result.GetType() == typeof(umbraco.MacroEngines.DynamicNull));
|
||||
//Assert.AreEqual(typeof(DynamicNull), result.GetType());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void String_Contains_Method()
|
||||
{
|
||||
var doc = GetDynamicNode(1046);
|
||||
|
||||
var paramVals = new Dictionary<string, object> { { "searchId", "1173" } };
|
||||
var result = doc.Children()
|
||||
.Where("selectedNodes.Contains(searchId)", paramVals)
|
||||
.FirstOrDefault();
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(4444, result.Id);
|
||||
|
||||
//don't find!
|
||||
paramVals = new Dictionary<string, object> { { "searchId", "1aaa173" } };
|
||||
result = doc.Children()
|
||||
.Where("selectedNodes.Contains(searchId)", paramVals)
|
||||
.FirstOrDefault();
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsTrue(result.GetType() == typeof (DynamicNull) || result.GetType() == typeof (umbraco.MacroEngines.DynamicNull));
|
||||
//Assert.AreEqual(typeof (DynamicNull), result.GetType());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void String_Split_Method()
|
||||
{
|
||||
var doc = GetDynamicNode(1046);
|
||||
|
||||
var paramVals = new Dictionary<string, object>
|
||||
{
|
||||
{ "splitTerm", new char[] { ',' } },
|
||||
{ "splitOptions", StringSplitOptions.RemoveEmptyEntries }
|
||||
};
|
||||
var result = doc.Children()
|
||||
.Where("selectedNodes.Split(splitTerm, splitOptions).Length == 3", paramVals)
|
||||
.FirstOrDefault();
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(4444, result.Id);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Complex_Linq()
|
||||
{
|
||||
var doc = GetDynamicNode(1173);
|
||||
|
||||
var paramVals = new Dictionary<string, object> {{"splitTerm", new char[] {','}}, {"searchId", "1173"}};
|
||||
var result = doc.Ancestors().OrderBy("level")
|
||||
.Single()
|
||||
.Descendants()
|
||||
.Where("selectedNodes != null && selectedNodes != String.Empty && selectedNodes.Split(splitTerm).Contains(searchId)", paramVals)
|
||||
.FirstOrDefault();
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(4444, result.Id);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Index()
|
||||
{
|
||||
@@ -132,7 +275,7 @@ namespace Umbraco.Tests.DynamicDocument
|
||||
|
||||
var found1 = doc.Children.GroupBy("DocumentTypeAlias");
|
||||
|
||||
var casted = (IEnumerable<IGrouping<object, IPublishedContent>>)(found1);
|
||||
var casted = (IEnumerable<IGrouping<object, dynamic>>)(found1);
|
||||
Assert.AreEqual(2, casted.Count());
|
||||
Assert.AreEqual(2, casted.Single(x => x.Key.ToString() == "Home").Count());
|
||||
Assert.AreEqual(1, casted.Single(x => x.Key.ToString() == "CustomDocument").Count());
|
||||
@@ -150,6 +293,18 @@ namespace Umbraco.Tests.DynamicDocument
|
||||
Assert.AreEqual(2, found2.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Children_Where_NodeTypeAlias()
|
||||
{
|
||||
var doc = GetDynamicNode(1046);
|
||||
|
||||
var found1 = doc.Children.Where("NodeTypeAlias == \"CustomDocument\"");
|
||||
var found2 = doc.Children.Where("NodeTypeAlias == \"Home\"");
|
||||
|
||||
Assert.AreEqual(1, found1.Count());
|
||||
Assert.AreEqual(2, found2.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Children_Order_By_Update_Date()
|
||||
{
|
||||
@@ -166,6 +321,22 @@ namespace Umbraco.Tests.DynamicDocument
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Children_Order_By_Update_Date_Descending()
|
||||
{
|
||||
var asDynamic = GetDynamicNode(1173);
|
||||
|
||||
var ordered = asDynamic.Children.OrderBy("UpdateDate desc");
|
||||
var casted = (IEnumerable<TDocument>)ordered;
|
||||
|
||||
var correctOrder = new[] { 1176, 1174, 1177, 1178 };
|
||||
for (var i = 0; i < correctOrder.Length; i++)
|
||||
{
|
||||
Assert.AreEqual(correctOrder[i], ((dynamic)casted.ElementAt(i)).Id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HasProperty()
|
||||
{
|
||||
@@ -372,7 +543,7 @@ namespace Umbraco.Tests.DynamicDocument
|
||||
Assert.IsNotNull(result);
|
||||
|
||||
var list = (IEnumerable<TDocument>)result;
|
||||
Assert.AreEqual(8, list.Count());
|
||||
Assert.AreEqual(9, list.Count());
|
||||
Assert.IsTrue(list.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1046, 1173, 1174, 1176, 1175, 4444 }));
|
||||
}
|
||||
|
||||
@@ -386,7 +557,7 @@ namespace Umbraco.Tests.DynamicDocument
|
||||
Assert.IsNotNull(result);
|
||||
|
||||
var list = (IEnumerable<TDocument>)result;
|
||||
Assert.AreEqual(7, list.Count());
|
||||
Assert.AreEqual(8, list.Count());
|
||||
Assert.IsTrue(list.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1173, 1174, 1176, 1175, 4444 }));
|
||||
}
|
||||
|
||||
@@ -453,6 +624,16 @@ namespace Umbraco.Tests.DynamicDocument
|
||||
|
||||
Assert.AreEqual((int) 1174, (int) result.Id);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods used in tests
|
||||
/// </summary>
|
||||
public static class TestExtensionMethods
|
||||
{
|
||||
public static bool ContainsValue(this string s, int val)
|
||||
{
|
||||
return s.Contains(val.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ namespace Umbraco.Tests.DynamicDocument
|
||||
/// Unit tests for IPublishedContent and extensions
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class DocumentTests : BaseRoutingTest
|
||||
public class PublishedContentDataTableTests : BaseRoutingTest
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -71,7 +71,7 @@ namespace Umbraco.Tests.DynamicDocument
|
||||
[Test]
|
||||
public void To_DataTable()
|
||||
{
|
||||
var doc = GetDocument(true, 1);
|
||||
var doc = GetContent(true, 1);
|
||||
var dt = doc.ChildrenAsTable();
|
||||
|
||||
Assert.AreEqual(11, dt.Columns.Count);
|
||||
@@ -90,7 +90,7 @@ namespace Umbraco.Tests.DynamicDocument
|
||||
[Test]
|
||||
public void To_DataTable_With_Filter()
|
||||
{
|
||||
var doc = GetDocument(true, 1);
|
||||
var doc = GetContent(true, 1);
|
||||
//change a doc type alias
|
||||
((TestPublishedContent) doc.Children.ElementAt(0)).DocumentTypeAlias = "DontMatch";
|
||||
|
||||
@@ -109,14 +109,14 @@ namespace Umbraco.Tests.DynamicDocument
|
||||
[Test]
|
||||
public void To_DataTable_No_Rows()
|
||||
{
|
||||
var doc = GetDocument(false, 1);
|
||||
var doc = GetContent(false, 1);
|
||||
var dt = doc.ChildrenAsTable();
|
||||
//will return an empty data table
|
||||
Assert.AreEqual(0, dt.Columns.Count);
|
||||
Assert.AreEqual(0, dt.Rows.Count);
|
||||
}
|
||||
|
||||
private IPublishedContent GetDocument(bool createChildren, int indexVals)
|
||||
private IPublishedContent GetContent(bool createChildren, int indexVals)
|
||||
{
|
||||
var d = new TestPublishedContent
|
||||
{
|
||||
@@ -149,9 +149,9 @@ namespace Umbraco.Tests.DynamicDocument
|
||||
{
|
||||
d.Children = new List<IPublishedContent>()
|
||||
{
|
||||
GetDocument(false, indexVals + 3),
|
||||
GetDocument(false, indexVals + 6),
|
||||
GetDocument(false, indexVals + 9)
|
||||
GetContent(false, indexVals + 3),
|
||||
GetContent(false, indexVals + 6),
|
||||
GetContent(false, indexVals + 9)
|
||||
};
|
||||
}
|
||||
if (!createChildren)
|
||||
@@ -51,7 +51,9 @@ namespace Umbraco.Tests.DynamicDocument
|
||||
</Home>
|
||||
<Home id=""1175"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""3"" createDate=""2012-07-20T18:08:01"" updateDate=""2012-07-20T18:49:32"" nodeName=""Sub 2"" urlName=""sub-2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1175"" isDoc=""""><content><![CDATA[]]></content>
|
||||
</Home>
|
||||
<CustomDocument id=""4444"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""4"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""Test"" urlName=""test-page"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,4444"" isDoc="""" />
|
||||
<CustomDocument id=""4444"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""4"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""Test"" urlName=""test-page"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,4444"" isDoc="""">
|
||||
<selectedNodes><![CDATA[1172,1176,1173]]></selectedNodes>
|
||||
</CustomDocument>
|
||||
</Home>
|
||||
<CustomDocument id=""1172"" parentID=""-1"" level=""1"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""Test"" urlName=""test-page"" writerName=""admin"" creatorName=""admin"" path=""-1,1172"" isDoc="""" />
|
||||
</root>";
|
||||
@@ -103,6 +105,19 @@ namespace Umbraco.Tests.DynamicDocument
|
||||
return doc;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Complex_Linq()
|
||||
{
|
||||
var doc = GetNode(1173);
|
||||
|
||||
var result = doc.Ancestors().OrderBy(x => x.Level)
|
||||
.Single()
|
||||
.Descendants()
|
||||
.FirstOrDefault(x => x.GetPropertyValue("selectedNodes", "").Split(',').Contains("1173"));
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Index()
|
||||
{
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ContentStores\PublishMediaStoreTests.cs" />
|
||||
<Compile Include="DynamicDocument\DocumentTests.cs" />
|
||||
<Compile Include="DynamicDocument\PublishedContentDataTableTests.cs" />
|
||||
<Compile Include="DynamicDocument\PublishedContentTests.cs" />
|
||||
<Compile Include="HtmlHelperExtensionMethodsTests.cs" />
|
||||
<Compile Include="LibraryTests.cs" />
|
||||
|
||||
@@ -293,9 +293,9 @@
|
||||
<Content Include="config\BaseRestExtensions.config">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<Content Include="config\BaseRestExtensions.Release.config">
|
||||
<None Include="config\BaseRestExtensions.Release.config">
|
||||
<DependentUpon>BaseRestExtensions.config</DependentUpon>
|
||||
</Content>
|
||||
</None>
|
||||
<None Include="config\log4net.Release.config">
|
||||
<DependentUpon>log4net.config</DependentUpon>
|
||||
</None>
|
||||
@@ -1149,7 +1149,6 @@
|
||||
<Content Include="umbraco\images\editor\insRazorMacro.png" />
|
||||
<Content Include="umbraco_client\Application\JQuery\jquery.hotkeys.js" />
|
||||
<Content Include="umbraco_client\MaskedInput\jquery.maskedinput-1.3.min.js" />
|
||||
<Content Include="umbraco_client\splitbutton\jquery.splitbutton.js" />
|
||||
<Content Include="umbraco_client\splitbutton\images\splitbutton_hover.png" />
|
||||
<Content Include="umbraco_client\splitbutton\images\splitbutton_downarrow.png" />
|
||||
<Content Include="umbraco_client\splitbutton\splitbutton.css" />
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RestExtensions>
|
||||
<!--
|
||||
<ext assembly="umbraco" type="umbraco.presentation.umbracoBase.library.member" alias="currentMember">
|
||||
<permission method="login" allowAll="true" />
|
||||
<permission method="logout" allowAll="true" />
|
||||
<permission method="id" allowAll="true" />
|
||||
<permission method="data" allowAll="true" />
|
||||
<permission method="logout" allowAll="true" />
|
||||
<permission method="setProperty" allowAll="false" />
|
||||
</ext>
|
||||
-->
|
||||
</RestExtensions>
|
||||
<BaseRestExtensions>
|
||||
<!--
|
||||
<extension alias="member" type="Umbraco.Web.BaseRest.MemberRest,umbraco">
|
||||
<method name="Login" allowAll="true" />
|
||||
<method name="Logout" allowAll="true" />
|
||||
<method name="GetCurrentMemberId" allowAll="true" />
|
||||
<method name="GetCurrentMember" allowAll="true" />
|
||||
<method name="GetCurrentMemberAsXml" allowAll="true" />
|
||||
<method name="SetProperty" allowAll="false" />
|
||||
</extension>
|
||||
-->
|
||||
<!--
|
||||
<extension alias="umbBlog" type="Runway.Blog.Library.Base,Runway.Blog">
|
||||
<method name="CreateComment" returnXml="false" allowAll="true" />
|
||||
<method name="GetGravatarImage" returnXml="false" allowAll="true" />
|
||||
</extension>
|
||||
-->
|
||||
</BaseRestExtensions>
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<BaseRestExtensions>
|
||||
<!--
|
||||
<extension alias="member" type="Umbraco.Web.BaseRest.MemberRest,umbraco">
|
||||
<method name="Login" allowAll="true" />
|
||||
<method name="Logout" allowAll="true" />
|
||||
@@ -8,6 +9,7 @@
|
||||
<method name="GetCurrentMemberAsXml" allowAll="true" />
|
||||
<method name="SetProperty" allowAll="false" />
|
||||
</extension>
|
||||
-->
|
||||
<!--
|
||||
<extension alias="umbBlog" type="Runway.Blog.Library.Base,Runway.Blog">
|
||||
<method name="CreateComment" returnXml="false" allowAll="true" />
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
<div class="container">
|
||||
<p>
|
||||
<strong>2. Getting a database setup for umbraco.</strong><br />
|
||||
For first time users, we recommend you select "quick-and-simple file-based database".
|
||||
For first time users, we recommend you select "quick-and-simple embedded database".
|
||||
This will install an easy to use database, that does
|
||||
not require any additional software to use.<br />
|
||||
Alternatively, you can install Microsoft SQL Server, which will require a bit more
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
</p>
|
||||
<p>
|
||||
As this is an upgrade, <strong>the wizard might skip steps</strong> that are only needed for new umbraco installations. It might also ask you questions you've already answered once. But do not worry,
|
||||
everything is in order. Click <strong>Lets get started</strong> below to begin your upgrade.
|
||||
everything is in order. Click <strong>Let's get started</strong> below to begin your upgrade.
|
||||
</p>
|
||||
<span class="enjoy">Enjoy!</span>
|
||||
</asp:PlaceHolder>
|
||||
@@ -43,7 +43,7 @@
|
||||
<!-- btn box -->
|
||||
<footer class="btn-box">
|
||||
<div class="t"> </div>
|
||||
<asp:LinkButton ID="btnNext" CssClass="btn btn-get" runat="server" OnClick="gotoNextStep"><span>Lets get started!</span></asp:LinkButton>
|
||||
<asp:LinkButton ID="btnNext" CssClass="btn btn-get" runat="server" OnClick="gotoNextStep"><span>Let's get started!</span></asp:LinkButton>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
@@ -35,6 +35,13 @@
|
||||
<strong id="username"><%=umbraco.BusinessLogic.User.GetCurrent().Name%></strong>
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span>
|
||||
<asp:Label runat="server" AssociatedControlID="currentpassword" ID="Label2"><%=umbraco.ui.Text("password") %>:</asp:Label>
|
||||
<asp:TextBox id="currentpassword" TextMode="password" CssClass="textfield" Runat="server"></asp:TextBox>
|
||||
<asp:RequiredFieldValidator runat="server" ControlToValidate="currentpassword" ID="RequiredFieldValidator1" ValidationGroup="changepass">*</asp:RequiredFieldValidator>
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span>
|
||||
<asp:Label runat="server" AssociatedControlID="password" ID="passwordLabel"><%=umbraco.ui.Text("passwordEnterNew") %>:</asp:Label>
|
||||
|
||||
@@ -136,9 +136,6 @@
|
||||
<HeaderTemplate>
|
||||
<table cellspacing="0" cellpadding="2" width="98%" border="0">
|
||||
<tr>
|
||||
<td class="propertyHeader">
|
||||
<%=umbraco.ui.Text("show",this.getUser())%>
|
||||
</td>
|
||||
<td class="propertyHeader">
|
||||
<%=umbraco.ui.Text("general", "alias",this.getUser())%>
|
||||
</td>
|
||||
@@ -153,9 +150,6 @@
|
||||
</HeaderTemplate>
|
||||
<ItemTemplate>
|
||||
<tr>
|
||||
<td class="propertyContent">
|
||||
<asp:CheckBox runat="server" ID="macroPropertyHidden" Checked='<%# macroIsVisible (DataBinder.Eval(Container.DataItem, "Public"))%>' />
|
||||
</td>
|
||||
<td class="propertyContent">
|
||||
<input type="hidden" id="macroPropertyID" runat="server" value='<%#DataBinder.Eval(Container.DataItem, "id")%>'
|
||||
name="macroPropertyID" />
|
||||
@@ -179,13 +173,10 @@
|
||||
<FooterTemplate>
|
||||
<tr>
|
||||
<td class="propertyContent">
|
||||
<asp:CheckBox runat="server" ID="macroPropertyHiddenNew" />
|
||||
<asp:TextBox runat="server" ID="macroPropertyAliasNew" Text='' OnTextChanged="macroPropertyCreate" />
|
||||
</td>
|
||||
<td class="propertyContent">
|
||||
<asp:TextBox runat="server" ID="macroPropertyAliasNew" Text='New Alias' OnTextChanged="macroPropertyCreate" />
|
||||
</td>
|
||||
<td class="propertyContent">
|
||||
<asp:TextBox runat="server" ID="macroPropertyNameNew" Text='New Name' />
|
||||
<asp:TextBox runat="server" ID="macroPropertyNameNew" Text='' />
|
||||
</td>
|
||||
<td class="propertyContent">
|
||||
<asp:DropDownList OnPreRender="AddChooseList" runat="server" ID="macroPropertyTypeNew"
|
||||
|
||||
@@ -4,15 +4,60 @@
|
||||
<%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %>
|
||||
<%@ Register TagPrefix="umb" Namespace="ClientDependency.Core.Controls" Assembly="ClientDependency.Core" %>
|
||||
<asp:Content ContentPlaceHolderID="head" runat="server">
|
||||
|
||||
<umb:CssInclude ID="CssInclude1" runat="server" FilePath="splitbutton/splitbutton.css"
|
||||
PathNameAlias="UmbracoClient" />
|
||||
<umb:JsInclude ID="JsInclude" runat="server" FilePath="splitbutton/jquery.splitbutton.js"
|
||||
PathNameAlias="UmbracoClient" Priority="1" />
|
||||
|
||||
<style>
|
||||
|
||||
#codeTemplateMenu , #macroMenu
|
||||
{
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
left:250px;
|
||||
background-color: #ddd;
|
||||
padding: 5px;
|
||||
display: none;
|
||||
max-height: 400px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
#macroMenu {
|
||||
left:110px;
|
||||
}
|
||||
.codeTemplate, .macro {
|
||||
padding-left: 5px;
|
||||
padding-top: 3px;
|
||||
cursor: pointer;
|
||||
|
||||
}
|
||||
.codeTemplate:hover, .macro:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
</style>
|
||||
<script language="javascript" type="text/javascript">
|
||||
jQuery(document).ready(function() {
|
||||
//macro split button
|
||||
jQuery('#sbMacro').splitbutton({menu:'#macroMenu'});
|
||||
|
||||
jQuery("#splitButtonMacro").appendTo("#splitButtonMacroPlaceHolder");
|
||||
jQuery("#selectMacro")
|
||||
.click(function() {
|
||||
jQuery("#macroMenu").toggle();
|
||||
});
|
||||
jQuery("#macroMenu").hover(
|
||||
function() { jQuery("#macroMenu").show(); },
|
||||
function() { jQuery("#macroMenu").hide(); }
|
||||
);
|
||||
jQuery("#selectRazor")
|
||||
.click(function() {
|
||||
jQuery("#codeTemplateMenu").toggle();
|
||||
});
|
||||
jQuery("#codeTemplateMenu").hover(
|
||||
function() { jQuery("#codeTemplateMenu").show(); },
|
||||
function() { jQuery("#codeTemplateMenu").hide(); }
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
jQuery(".macro").click(function(){
|
||||
var alias = jQuery(this).attr("rel");
|
||||
if(jQuery(this).attr("params") == "1")
|
||||
@@ -24,10 +69,10 @@
|
||||
insertMacro(alias);
|
||||
}
|
||||
});
|
||||
applySplitButtonOverflow('mcontainer','innerc','macroMenu','.macro', 'showMoreMacros');
|
||||
|
||||
|
||||
//razor macro split button
|
||||
jQuery('#sb').splitbutton({menu:'#codeTemplateMenu'});
|
||||
// jQuery('#sb').splitbutton({menu:'#codeTemplateMenu'});
|
||||
jQuery("#splitButton").appendTo("#splitButtonPlaceHolder");
|
||||
|
||||
jQuery(".codeTemplate").click(function(){
|
||||
@@ -185,12 +230,12 @@
|
||||
</cc1:PropertyPanel>
|
||||
</cc1:Pane>
|
||||
</cc1:UmbracoPanel>
|
||||
|
||||
<div id="splitButton" style="display: inline; height: 23px; vertical-align: top;">
|
||||
<a href="javascript:insertCodeBlock();" id="sb" class="sbLink">
|
||||
<img alt="Insert Inline Razor Macro" src="../images/editor/insRazorMacro.png" title="Insert Inline Razor Macro"
|
||||
style="vertical-align: top;">
|
||||
</a>
|
||||
<a href="#" id="sb" class="sbLink l-btn l-btn-plain"><span class="l-btn-left"><span class="l-btn-text"><img alt="Insert Inline Razor Macro" src="../images/editor/insRazorMacro.png" title="Insert Inline Razor Macro" style="vertical-align: top;" onclick="javascript:insertCodeBlock();">
|
||||
<span class="s-btn-downarrow" id="selectRazor"> </span></span></span></a>
|
||||
</div>
|
||||
|
||||
<div id="codeTemplateMenu" style="width: 285px;">
|
||||
<asp:Repeater ID="rpt_codeTemplates" runat="server">
|
||||
<ItemTemplate>
|
||||
@@ -200,11 +245,10 @@
|
||||
</ItemTemplate>
|
||||
</asp:Repeater>
|
||||
</div>
|
||||
|
||||
<div id="splitButtonMacro" style="display: inline; height: 23px; vertical-align: top;">
|
||||
<a href="javascript:openMacroModal();" id="sbMacro" class="sbLink">
|
||||
<img alt="Insert Macro" src="../images/editor/insMacroSB.png" title="Insert Macro"
|
||||
style="vertical-align: top;">
|
||||
</a>
|
||||
<a href="#" id="sbMacro" class="sbLink l-btn l-btn-plain"><span class="l-btn-left"><span class="l-btn-text"><img alt="Insert Macro" src="../images/editor/insMacroSB.png" title="Insert Macro" style="vertical-align: top;" onclick="javascript:openMacroModal();">
|
||||
<span class="s-btn-downarrow" id="selectMacro"> </span></span></span></a>
|
||||
</div>
|
||||
<div id="macroMenu" style="width: 285px">
|
||||
<asp:Repeater ID="rpt_macros" runat="server">
|
||||
|
||||
@@ -56,14 +56,19 @@ namespace Umbraco.Web.UI.Umbraco.Settings.Views
|
||||
|
||||
var li = new ListItem(t.Text, t.Id.ToString());
|
||||
li.Attributes.Add("id", t.Alias.Replace(" ", ""));
|
||||
|
||||
if (t.Id == _template.MasterTemplate)
|
||||
selectedTemplate = t.Alias.Replace(" ", "");
|
||||
|
||||
MasterTemplate.Items.Add(li);
|
||||
MasterTemplate.Items.Add(li);
|
||||
}
|
||||
|
||||
MasterTemplate.SelectedValue = selectedTemplate;
|
||||
try
|
||||
{
|
||||
if (_template.MasterTemplate > 0)
|
||||
MasterTemplate.SelectedValue = _template.MasterTemplate.ToString();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
}
|
||||
|
||||
MasterTemplate.SelectedValue = selectedTemplate;
|
||||
|
||||
NameTxt.Text = _template.GetRawText();
|
||||
AliasTxt.Text = _template.Alias;
|
||||
|
||||
@@ -488,6 +488,10 @@ guiEditor {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.treePickerTitle {
|
||||
border-bottom: 1px dotted #333;
|
||||
}
|
||||
|
||||
.umbMacroHolder
|
||||
{
|
||||
margin: 5px;
|
||||
@@ -708,4 +712,13 @@ guiEditor {
|
||||
background: -moz-linear-gradient(100% 100% 90deg, #fefefe, #ddd);
|
||||
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#ddd), to(#fefefe));
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.treePickerTooltip {
|
||||
display: none;
|
||||
position: absolute;
|
||||
border: 1px solid #333;
|
||||
background-color: #fff8cb;
|
||||
padding: 3px;
|
||||
color: #000;
|
||||
}
|
||||
@@ -7,29 +7,30 @@ namespace Umbraco.Web.Dynamics
|
||||
{
|
||||
internal static class DynamicExpression
|
||||
{
|
||||
public static bool ConvertDynamicNullToBooleanFalse = false;
|
||||
public static Expression Parse(Type resultType, string expression, bool convertDynamicNullToBooleanFalse, params object[] values)
|
||||
//public static bool ConvertDynamicNullToBooleanFalse = false;
|
||||
|
||||
public static Expression Parse<T>(Type resultType, string expression, bool convertDynamicNullToBooleanFalse, params object[] values)
|
||||
{
|
||||
ConvertDynamicNullToBooleanFalse = convertDynamicNullToBooleanFalse;
|
||||
ExpressionParser parser = new ExpressionParser(null, expression, values);
|
||||
//ConvertDynamicNullToBooleanFalse = convertDynamicNullToBooleanFalse;
|
||||
var parser = new ExpressionParser<T>(null, expression, values, convertDynamicNullToBooleanFalse);
|
||||
return parser.Parse(resultType);
|
||||
}
|
||||
|
||||
public static LambdaExpression ParseLambda(Type itType, Type resultType, string expression, bool convertDynamicNullToBooleanFalse, params object[] values)
|
||||
public static LambdaExpression ParseLambda<T>(Type itType, Type resultType, string expression, bool convertDynamicNullToBooleanFalse, params object[] values)
|
||||
{
|
||||
return ParseLambda(new ParameterExpression[] { Expression.Parameter(itType, "") }, resultType, expression, convertDynamicNullToBooleanFalse, values);
|
||||
return ParseLambda<T>(new ParameterExpression[] { Expression.Parameter(itType, "") }, resultType, expression, convertDynamicNullToBooleanFalse, values);
|
||||
}
|
||||
|
||||
public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type resultType, string expression, bool convertDynamicNullToBooleanFalse, params object[] values)
|
||||
public static LambdaExpression ParseLambda<T>(ParameterExpression[] parameters, Type resultType, string expression, bool convertDynamicNullToBooleanFalse, params object[] values)
|
||||
{
|
||||
ConvertDynamicNullToBooleanFalse = convertDynamicNullToBooleanFalse;
|
||||
ExpressionParser parser = new ExpressionParser(parameters, expression, values);
|
||||
//ConvertDynamicNullToBooleanFalse = convertDynamicNullToBooleanFalse;
|
||||
var parser = new ExpressionParser<T>(parameters, expression, values, convertDynamicNullToBooleanFalse);
|
||||
return Expression.Lambda(parser.Parse(resultType), parameters);
|
||||
}
|
||||
|
||||
public static Expression<Func<T, S>> ParseLambda<T, S>(string expression, bool convertDynamicNullToBooleanFalse, params object[] values)
|
||||
public static Expression<Func<T, S>> ParseLambda<TDoc, T, S>(string expression, bool convertDynamicNullToBooleanFalse, params object[] values)
|
||||
{
|
||||
return (Expression<Func<T, S>>)ParseLambda(typeof(T), typeof(S), expression, convertDynamicNullToBooleanFalse, values);
|
||||
return (Expression<Func<T, S>>)ParseLambda<TDoc>(typeof(T), typeof(S), expression, convertDynamicNullToBooleanFalse, values);
|
||||
}
|
||||
|
||||
public static Type CreateClass(params DynamicProperty[] properties)
|
||||
|
||||
@@ -6,7 +6,7 @@ using Umbraco.Web.Models;
|
||||
|
||||
namespace Umbraco.Web.Dynamics
|
||||
{
|
||||
internal static class DynamicPublishedContentListOrdering
|
||||
public static class DynamicPublishedContentListOrdering
|
||||
{
|
||||
|
||||
private static TOut Reduce<TOut>(Func<DynamicPublishedContent, TOut> func, DynamicPublishedContent publishedContent)
|
||||
@@ -38,7 +38,7 @@ namespace Umbraco.Web.Dynamics
|
||||
}
|
||||
return (TOut)value;
|
||||
}
|
||||
internal static IOrderedQueryable<DynamicPublishedContent> OrderBy(object source, object key)
|
||||
public static IOrderedQueryable<DynamicPublishedContent> OrderBy(object source, object key)
|
||||
{
|
||||
IEnumerable<DynamicPublishedContent> typedSource = source as IEnumerable<DynamicPublishedContent>;
|
||||
LambdaExpression lambda = key as LambdaExpression;
|
||||
@@ -92,7 +92,7 @@ namespace Umbraco.Web.Dynamics
|
||||
}
|
||||
return result;
|
||||
}
|
||||
internal static IOrderedQueryable<DynamicPublishedContent> ThenBy(object source, object key)
|
||||
public static IOrderedQueryable<DynamicPublishedContent> ThenBy(object source, object key)
|
||||
{
|
||||
IOrderedQueryable<DynamicPublishedContent> typedSource = source as IOrderedQueryable<DynamicPublishedContent>;
|
||||
LambdaExpression lambda = key as LambdaExpression;
|
||||
@@ -143,7 +143,7 @@ namespace Umbraco.Web.Dynamics
|
||||
}
|
||||
return result;
|
||||
}
|
||||
internal static IOrderedQueryable<DynamicPublishedContent> OrderByDescending(object source, object key)
|
||||
public static IOrderedQueryable<DynamicPublishedContent> OrderByDescending(object source, object key)
|
||||
{
|
||||
IEnumerable<DynamicPublishedContent> typedSource = source as IEnumerable<DynamicPublishedContent>;
|
||||
LambdaExpression lambda = key as LambdaExpression;
|
||||
@@ -194,7 +194,7 @@ namespace Umbraco.Web.Dynamics
|
||||
}
|
||||
return result;
|
||||
}
|
||||
internal static IOrderedQueryable<DynamicPublishedContent> ThenByDescending(object source, object key)
|
||||
public static IOrderedQueryable<DynamicPublishedContent> ThenByDescending(object source, object key)
|
||||
{
|
||||
IOrderedQueryable<DynamicPublishedContent> typedSource = source as IOrderedQueryable<DynamicPublishedContent>;
|
||||
LambdaExpression lambda = key as LambdaExpression;
|
||||
|
||||
@@ -15,30 +15,30 @@ namespace Umbraco.Web.Dynamics
|
||||
{
|
||||
public static IQueryable<T> Where<T>(this IQueryable<T> source, string predicate, params object[] values)
|
||||
{
|
||||
return (IQueryable<T>)Where((IQueryable)source, predicate, values);
|
||||
return (IQueryable<T>)Where<T>((IQueryable)source, predicate, values);
|
||||
}
|
||||
|
||||
public static IQueryable Where(this IQueryable source, string predicate, params object[] values)
|
||||
public static IQueryable Where<T>(this IQueryable source, string predicate, params object[] values)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
if (predicate == null) throw new ArgumentNullException("predicate");
|
||||
LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(bool), predicate, true, values);
|
||||
if (lambda.Parameters.Count > 0 && lambda.Parameters[0].Type == typeof(DynamicPublishedContent))
|
||||
LambdaExpression lambda = DynamicExpression.ParseLambda<T>(source.ElementType, typeof(bool), predicate, true, values);
|
||||
if (lambda.Parameters.Count > 0 && lambda.Parameters[0].Type == typeof(T))
|
||||
{
|
||||
//source list is DynamicNode and the lambda returns a Func<object>
|
||||
IQueryable<DynamicPublishedContent> typedSource = source as IQueryable<DynamicPublishedContent>;
|
||||
IQueryable<T> typedSource = source as IQueryable<T>;
|
||||
var compiledFunc = lambda.Compile();
|
||||
Func<DynamicPublishedContent, object> func = null;
|
||||
Func<DynamicPublishedContent, bool> boolFunc = null;
|
||||
if (compiledFunc is Func<DynamicPublishedContent, object>)
|
||||
Func<T, object> func = null;
|
||||
Func<T, bool> boolFunc = null;
|
||||
if (compiledFunc is Func<T, object>)
|
||||
{
|
||||
func = (Func<DynamicPublishedContent, object>)compiledFunc;
|
||||
func = (Func<T, object>)compiledFunc;
|
||||
}
|
||||
if (compiledFunc is Func<DynamicPublishedContent, bool>)
|
||||
if (compiledFunc is Func<T, bool>)
|
||||
{
|
||||
boolFunc = (Func<DynamicPublishedContent, bool>)compiledFunc;
|
||||
boolFunc = (Func<T, bool>)compiledFunc;
|
||||
}
|
||||
return typedSource.Where(delegate(DynamicPublishedContent node)
|
||||
return typedSource.Where(delegate(T node)
|
||||
{
|
||||
object value = -1;
|
||||
//value = func(node);
|
||||
@@ -48,13 +48,13 @@ namespace Umbraco.Web.Dynamics
|
||||
if (func != null)
|
||||
{
|
||||
var firstFuncResult = func(node);
|
||||
if (firstFuncResult is Func<DynamicPublishedContent, object>)
|
||||
if (firstFuncResult is Func<T, object>)
|
||||
{
|
||||
value = (firstFuncResult as Func<DynamicPublishedContent, object>)(node);
|
||||
value = (firstFuncResult as Func<T, object>)(node);
|
||||
}
|
||||
if (firstFuncResult is Func<DynamicPublishedContent, bool>)
|
||||
if (firstFuncResult is Func<T, bool>)
|
||||
{
|
||||
value = (firstFuncResult as Func<DynamicPublishedContent, bool>)(node);
|
||||
value = (firstFuncResult as Func<T, bool>)(node);
|
||||
}
|
||||
if (firstFuncResult is bool)
|
||||
{
|
||||
@@ -88,28 +88,28 @@ namespace Umbraco.Web.Dynamics
|
||||
}
|
||||
}
|
||||
|
||||
public static IQueryable Select(this IQueryable<DynamicPublishedContent> source, string selector, params object[] values)
|
||||
public static IQueryable Select<T>(this IQueryable<T> source, string selector, params object[] values)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
if (selector == null) throw new ArgumentNullException("selector");
|
||||
LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(object), selector, false, values);
|
||||
if (lambda.Parameters.Count > 0 && lambda.Parameters[0].Type == typeof(DynamicPublishedContent))
|
||||
LambdaExpression lambda = DynamicExpression.ParseLambda<T>(source.ElementType, typeof(object), selector, false, values);
|
||||
if (lambda.Parameters.Count > 0 && lambda.Parameters[0].Type == typeof(T))
|
||||
{
|
||||
//source list is DynamicNode and the lambda returns a Func<object>
|
||||
IQueryable<DynamicPublishedContent> typedSource = source as IQueryable<DynamicPublishedContent>;
|
||||
IQueryable<T> typedSource = source as IQueryable<T>;
|
||||
var compiledFunc = lambda.Compile();
|
||||
Func<DynamicPublishedContent, object> func = null;
|
||||
if (compiledFunc is Func<DynamicPublishedContent, object>)
|
||||
Func<T, object> func = null;
|
||||
if (compiledFunc is Func<T, object>)
|
||||
{
|
||||
func = (Func<DynamicPublishedContent, object>)compiledFunc;
|
||||
func = (Func<T, object>)compiledFunc;
|
||||
}
|
||||
return typedSource.Select(delegate(DynamicPublishedContent node)
|
||||
return typedSource.Select(delegate(T node)
|
||||
{
|
||||
object value = null;
|
||||
value = func(node);
|
||||
if (value is Func<DynamicPublishedContent, object>)
|
||||
if (value is Func<T, object>)
|
||||
{
|
||||
var innerValue = (value as Func<DynamicPublishedContent, object>)(node);
|
||||
var innerValue = (value as Func<T, object>)(node);
|
||||
return innerValue;
|
||||
}
|
||||
return value;
|
||||
@@ -125,17 +125,17 @@ namespace Umbraco.Web.Dynamics
|
||||
}
|
||||
}
|
||||
|
||||
public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering, params object[] values)
|
||||
public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering, Func<Type> getDynamicListTypeCallback, params object[] values)
|
||||
{
|
||||
return (IQueryable<T>)OrderBy((IQueryable)source, ordering, values);
|
||||
return (IQueryable<T>)OrderBy<T>((IQueryable)source, ordering, getDynamicListTypeCallback, values);
|
||||
}
|
||||
|
||||
public static IQueryable OrderBy(this IQueryable source, string ordering, params object[] values)
|
||||
public static IQueryable OrderBy<T>(this IQueryable source, string ordering, Func<Type> getDynamicListTypeCallback, params object[] values)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
if (ordering == null) throw new ArgumentNullException("ordering");
|
||||
|
||||
IQueryable<DynamicPublishedContent> typedSource = source as IQueryable<DynamicPublishedContent>;
|
||||
IQueryable<T> typedSource = source as IQueryable<T>;
|
||||
if (!ordering.Contains(","))
|
||||
{
|
||||
bool descending = false;
|
||||
@@ -150,11 +150,11 @@ namespace Umbraco.Web.Dynamics
|
||||
descending = true;
|
||||
}
|
||||
|
||||
LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(object), ordering, false, values);
|
||||
if (lambda.Parameters.Count > 0 && lambda.Parameters[0].Type == typeof(DynamicPublishedContent))
|
||||
LambdaExpression lambda = DynamicExpression.ParseLambda<T>(source.ElementType, typeof(object), ordering, false, values);
|
||||
if (lambda.Parameters.Count > 0 && lambda.Parameters[0].Type == typeof(T))
|
||||
{
|
||||
//source list is DynamicNode and the lambda returns a Func<object>
|
||||
Func<DynamicPublishedContent, object> func = (Func<DynamicPublishedContent, object>)lambda.Compile();
|
||||
Func<T, object> func = (Func<T, object>)lambda.Compile();
|
||||
//get the values out
|
||||
var query = typedSource.ToList().ConvertAll(item => new { node = item, key = EvaluateDynamicNodeFunc(item, func) });
|
||||
if (query.Count == 0)
|
||||
@@ -197,7 +197,7 @@ namespace Umbraco.Web.Dynamics
|
||||
|
||||
ParameterExpression[] parameters = new ParameterExpression[] {
|
||||
Expression.Parameter(source.ElementType, "") };
|
||||
ExpressionParser parser = new ExpressionParser(parameters, ordering, values);
|
||||
var parser = new ExpressionParser<T>(parameters, ordering, values, false);
|
||||
IEnumerable<DynamicOrdering> orderings = parser.ParseOrdering();
|
||||
Expression queryExpr = source.Expression;
|
||||
string methodAsc = "OrderBy";
|
||||
@@ -216,7 +216,7 @@ namespace Umbraco.Web.Dynamics
|
||||
//reroute each stacked Expression.Call into our own methods that know how to deal
|
||||
//with DynamicNode
|
||||
queryExpr = Expression.Call(
|
||||
typeof(DynamicPublishedContentListOrdering),
|
||||
getDynamicListTypeCallback(),
|
||||
o.Ascending ? methodAsc : methodDesc,
|
||||
null,
|
||||
queryExpr,
|
||||
@@ -248,13 +248,13 @@ namespace Umbraco.Web.Dynamics
|
||||
return null;
|
||||
}
|
||||
}
|
||||
private static object EvaluateDynamicNodeFunc(DynamicPublishedContent publishedContent, Func<DynamicPublishedContent, object> func)
|
||||
private static object EvaluateDynamicNodeFunc<T>(T publishedContent, Func<T, object> func)
|
||||
{
|
||||
object value = -1;
|
||||
var firstFuncResult = func(publishedContent);
|
||||
if (firstFuncResult is Func<DynamicPublishedContent, object>)
|
||||
if (firstFuncResult is Func<T, object>)
|
||||
{
|
||||
value = (firstFuncResult as Func<DynamicPublishedContent, object>)(publishedContent);
|
||||
value = (firstFuncResult as Func<T, object>)(publishedContent);
|
||||
}
|
||||
if (firstFuncResult.GetType().IsValueType || firstFuncResult is string)
|
||||
{
|
||||
@@ -282,13 +282,13 @@ namespace Umbraco.Web.Dynamics
|
||||
source.Expression, Expression.Constant(count)));
|
||||
}
|
||||
|
||||
public static IQueryable GroupBy(this IQueryable source, string keySelector, string elementSelector, params object[] values)
|
||||
public static IQueryable GroupBy<T>(this IQueryable source, string keySelector, string elementSelector, params object[] values)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
if (keySelector == null) throw new ArgumentNullException("keySelector");
|
||||
if (elementSelector == null) throw new ArgumentNullException("elementSelector");
|
||||
LambdaExpression keyLambda = DynamicExpression.ParseLambda(source.ElementType, null, keySelector, true, values);
|
||||
LambdaExpression elementLambda = DynamicExpression.ParseLambda(source.ElementType, null, elementSelector, true, values);
|
||||
LambdaExpression keyLambda = DynamicExpression.ParseLambda<T>(source.ElementType, null, keySelector, true, values);
|
||||
LambdaExpression elementLambda = DynamicExpression.ParseLambda<T>(source.ElementType, null, elementSelector, true, values);
|
||||
return source.Provider.CreateQuery(
|
||||
Expression.Call(
|
||||
typeof(Queryable), "GroupBy",
|
||||
|
||||
@@ -10,7 +10,7 @@ using Umbraco.Web.Models;
|
||||
|
||||
namespace Umbraco.Web.Dynamics
|
||||
{
|
||||
internal class ExpressionParser
|
||||
internal class ExpressionParser<T>
|
||||
{
|
||||
struct Token
|
||||
{
|
||||
@@ -200,12 +200,13 @@ namespace Umbraco.Web.Dynamics
|
||||
Dictionary<Expression, string> literals;
|
||||
ParameterExpression it;
|
||||
string text;
|
||||
private readonly bool _flagConvertDynamicNullToBooleanFalse;
|
||||
int textPos;
|
||||
int textLen;
|
||||
char ch;
|
||||
Token token;
|
||||
|
||||
public ExpressionParser(ParameterExpression[] parameters, string expression, object[] values)
|
||||
public ExpressionParser(ParameterExpression[] parameters, string expression, object[] values, bool flagConvertDynamicNullToBooleanFalse)
|
||||
{
|
||||
if (expression == null) throw new ArgumentNullException("expression");
|
||||
if (keywords == null) keywords = CreateKeywords();
|
||||
@@ -214,6 +215,7 @@ namespace Umbraco.Web.Dynamics
|
||||
if (parameters != null) ProcessParameters(parameters);
|
||||
if (values != null) ProcessValues(values);
|
||||
text = expression;
|
||||
_flagConvertDynamicNullToBooleanFalse = flagConvertDynamicNullToBooleanFalse;
|
||||
textLen = text.Length;
|
||||
SetTextPos(0);
|
||||
NextToken();
|
||||
@@ -510,7 +512,7 @@ namespace Umbraco.Web.Dynamics
|
||||
(expr as LambdaExpression).Parameters.CopyTo(parameters, 0);
|
||||
var invokedExpr = Expression.Invoke(expr, parameters);
|
||||
var not = Expression.Not(Expression.TypeAs(invokedExpr, typeof(Nullable<bool>)));
|
||||
expr = Expression.Lambda<Func<DynamicPublishedContent, bool>>(
|
||||
expr = Expression.Lambda<Func<T, bool>>(
|
||||
Expression.Condition(
|
||||
Expression.Property(not, "HasValue"),
|
||||
Expression.Property(not, "Value"),
|
||||
@@ -839,6 +841,11 @@ namespace Umbraco.Web.Dynamics
|
||||
|
||||
Expression ParseMemberAccess(Type type, Expression instance)
|
||||
{
|
||||
//NOTE: SD: There is a lot of string checking going on here and I'm 99% sure this can all be done better
|
||||
// in a more generic sense to support any types with any extension methods, etc...
|
||||
// Too bad whoever wrote this decided not to put any code comments in :(
|
||||
// This is how to support method calls, etc... in dynamic statements.
|
||||
|
||||
if (instance != null) type = instance.Type;
|
||||
int errorPos = token.Pos;
|
||||
string id = GetIdentifier();
|
||||
@@ -857,24 +864,33 @@ namespace Umbraco.Web.Dynamics
|
||||
Expression[] args = ParseArgumentList();
|
||||
MethodBase mb;
|
||||
LambdaExpression instanceAsString = null;
|
||||
ParameterExpression instanceExpression = Expression.Parameter(typeof(DynamicPublishedContent), "instance");
|
||||
ParameterExpression instanceExpression = Expression.Parameter(typeof(T), "instance");
|
||||
if (type.IsGenericType && type != typeof(string))
|
||||
{
|
||||
var typeArgs = type.GetGenericArguments();
|
||||
if (typeArgs[0] == typeof(DynamicPublishedContent))
|
||||
if (typeArgs[0] == typeof(T))
|
||||
{
|
||||
if (instance != null && instance is LambdaExpression)
|
||||
{
|
||||
{
|
||||
//not sure why this is object or why we need to do this but if we change it, things die...
|
||||
//also not sure why it is changed to string, i think this might be to ensure string methods are supported
|
||||
//but seems to me that we then won't support other types of methods?
|
||||
if (typeArgs[1] == typeof(object))
|
||||
{
|
||||
instanceAsString = StringFormat(instance as LambdaExpression, instanceExpression);
|
||||
type = typeof(string);
|
||||
}
|
||||
if (typeArgs[1] == typeof(string))
|
||||
else if (typeArgs[1] == typeof(string))
|
||||
{
|
||||
instanceAsString = instance as LambdaExpression;
|
||||
type = typeof(string);
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// instanceAsString = instance as LambdaExpression;
|
||||
// type = typeArgs[1];
|
||||
//}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -882,6 +898,10 @@ namespace Umbraco.Web.Dynamics
|
||||
{
|
||||
case 0:
|
||||
//not found
|
||||
|
||||
//SD: I have yet to see extension methods actually being called in the dynamic parsing... need to unit test these
|
||||
// scenarios and figure out why all this type checking occurs.
|
||||
|
||||
if (type == typeof(string) && instanceAsString != null)
|
||||
{
|
||||
Expression[] newArgs = (new List<Expression>() { Expression.Invoke(instanceAsString, instanceExpression) }).Concat(args).ToArray();
|
||||
@@ -932,19 +952,19 @@ namespace Umbraco.Web.Dynamics
|
||||
//this will invoke TryGetMember (but wrapped in an expression tree)
|
||||
//so that when it's evaluated, DynamicNode should be supported
|
||||
|
||||
ParameterExpression instanceExpression = Expression.Parameter(typeof(DynamicPublishedContent), "instance");
|
||||
ParameterExpression instanceExpression = Expression.Parameter(typeof(T), "instance");
|
||||
ParameterExpression convertDynamicNullToBooleanFalse = Expression.Parameter(typeof(bool), "convertDynamicNullToBooleanFalse");
|
||||
ParameterExpression result = Expression.Parameter(typeof(object), "result");
|
||||
ParameterExpression binder = Expression.Variable(typeof(DynamicQueryableGetMemberBinder), "binder");
|
||||
ParameterExpression ignoreCase = Expression.Variable(typeof(bool), "ignoreCase");
|
||||
ConstructorInfo getMemberBinderConstructor = typeof(DynamicQueryableGetMemberBinder).GetConstructor(new Type[] { typeof(string), typeof(bool) });
|
||||
LabelTarget blockReturnLabel = Expression.Label(typeof(object));
|
||||
MethodInfo method = typeof(DynamicPublishedContent).GetMethod("TryGetMember");
|
||||
MethodInfo method = typeof(T).GetMethod("TryGetMember");
|
||||
|
||||
BlockExpression block = Expression.Block(
|
||||
typeof(object),
|
||||
new[] { ignoreCase, binder, result, convertDynamicNullToBooleanFalse },
|
||||
Expression.Assign(convertDynamicNullToBooleanFalse, Expression.Constant(DynamicExpression.ConvertDynamicNullToBooleanFalse, typeof(bool))),
|
||||
Expression.Assign(convertDynamicNullToBooleanFalse, Expression.Constant(_flagConvertDynamicNullToBooleanFalse, typeof(bool))),
|
||||
Expression.Assign(ignoreCase, Expression.Constant(false, typeof(bool))),
|
||||
Expression.Assign(binder, Expression.New(getMemberBinderConstructor, Expression.Constant(id, typeof(string)), ignoreCase)),
|
||||
Expression.Assign(result, Expression.Constant(null)),
|
||||
@@ -960,10 +980,10 @@ namespace Umbraco.Web.Dynamics
|
||||
Expression.Return(blockReturnLabel, result),
|
||||
Expression.Label(blockReturnLabel, Expression.Constant(-2, typeof(object)))
|
||||
);
|
||||
LambdaExpression lax = Expression.Lambda<Func<DynamicPublishedContent, object>>(block, instanceExpression);
|
||||
LambdaExpression lax = Expression.Lambda<Func<T, object>>(block, instanceExpression);
|
||||
return lax;
|
||||
}
|
||||
if (typeof(Func<DynamicPublishedContent, object>).IsAssignableFrom(type))
|
||||
if (typeof(Func<T, object>).IsAssignableFrom(type))
|
||||
{
|
||||
//accessing a property off an already resolved DynamicNode TryGetMember call
|
||||
//e.g. uBlogsyPostDate.Date
|
||||
@@ -974,14 +994,14 @@ namespace Umbraco.Web.Dynamics
|
||||
ParameterExpression result = Expression.Parameter(typeof(object), "result");
|
||||
ParameterExpression idParam = Expression.Parameter(typeof(string), "id");
|
||||
ParameterExpression lambdaResult = Expression.Parameter(typeof(object), "lambdaResult");
|
||||
ParameterExpression lambdaInstanceExpression = Expression.Parameter(typeof(DynamicPublishedContent), "lambdaInstanceExpression");
|
||||
ParameterExpression instanceExpression = Expression.Parameter(typeof(Func<DynamicPublishedContent, object>), "instance");
|
||||
ParameterExpression lambdaInstanceExpression = Expression.Parameter(typeof(T), "lambdaInstanceExpression");
|
||||
ParameterExpression instanceExpression = Expression.Parameter(typeof(Func<T, object>), "instance");
|
||||
LabelTarget blockReturnLabel = Expression.Label(typeof(object));
|
||||
|
||||
BlockExpression block = Expression.Block(
|
||||
typeof(object),
|
||||
new[] { lambdaResult, result, idParam, convertDynamicNullToBooleanFalse },
|
||||
Expression.Assign(convertDynamicNullToBooleanFalse, Expression.Constant(DynamicExpression.ConvertDynamicNullToBooleanFalse, typeof(bool))),
|
||||
Expression.Assign(convertDynamicNullToBooleanFalse, Expression.Constant(_flagConvertDynamicNullToBooleanFalse, typeof(bool))),
|
||||
Expression.Assign(lambdaResult, Expression.Invoke(instance, lambdaInstanceExpression)),
|
||||
Expression.Assign(result, Expression.Call(ReflectPropertyValue, lambdaResult, Expression.Constant(id))),
|
||||
Expression.IfThen(
|
||||
@@ -994,7 +1014,7 @@ namespace Umbraco.Web.Dynamics
|
||||
Expression.Return(blockReturnLabel, result),
|
||||
Expression.Label(blockReturnLabel, Expression.Constant(-2, typeof(object)))
|
||||
);
|
||||
LambdaExpression lax = Expression.Lambda<Func<DynamicPublishedContent, object>>(block, lambdaInstanceExpression);
|
||||
LambdaExpression lax = Expression.Lambda<Func<T, object>>(block, lambdaInstanceExpression);
|
||||
return lax;
|
||||
}
|
||||
}
|
||||
@@ -1020,21 +1040,11 @@ namespace Umbraco.Web.Dynamics
|
||||
return null;
|
||||
}
|
||||
private static Expression CallMethodOnDynamicNode(Expression instance, Expression[] args, LambdaExpression instanceAsString, ParameterExpression instanceExpression, MethodInfo method, bool isStatic)
|
||||
{
|
||||
ConstantExpression defaultReturnValue = Expression.Constant(null, typeof(object));
|
||||
{
|
||||
Type methodReturnType = method.ReturnType;
|
||||
switch (methodReturnType.Name)
|
||||
{
|
||||
case "String":
|
||||
defaultReturnValue = Expression.Constant(null, typeof(string));
|
||||
break;
|
||||
case "Int32":
|
||||
defaultReturnValue = Expression.Constant(0, typeof(int));
|
||||
break;
|
||||
case "Boolean":
|
||||
defaultReturnValue = Expression.Constant(false, typeof(bool));
|
||||
break;
|
||||
}
|
||||
|
||||
var defaultReturnValue = Expression.Constant(methodReturnType.GetDefaultValue(), methodReturnType);
|
||||
|
||||
ParameterExpression result = Expression.Parameter(method.ReturnType, "result");
|
||||
LabelTarget blockReturnLabel = Expression.Label(method.ReturnType);
|
||||
BlockExpression block = Expression.Block(
|
||||
@@ -1050,16 +1060,24 @@ namespace Umbraco.Web.Dynamics
|
||||
Expression.Label(blockReturnLabel, defaultReturnValue)
|
||||
);
|
||||
|
||||
switch (methodReturnType.Name)
|
||||
{
|
||||
case "String":
|
||||
return Expression.Lambda<Func<DynamicPublishedContent, string>>(block, instanceExpression);
|
||||
case "Int32":
|
||||
return Expression.Lambda<Func<DynamicPublishedContent, int>>(block, instanceExpression);
|
||||
case "Boolean":
|
||||
return Expression.Lambda<Func<DynamicPublishedContent, bool>>(block, instanceExpression);
|
||||
}
|
||||
return Expression.Call(instance, (MethodInfo)method, args);
|
||||
Type func = typeof(Func<,>);
|
||||
Type generic = func.MakeGenericType(typeof(T), methodReturnType);
|
||||
return Expression.Lambda(generic, block, instanceExpression);
|
||||
|
||||
//if (methodReturnType == typeof(string))
|
||||
// return Expression.Lambda<Func<T, string>>(block, instanceExpression);
|
||||
//if (methodReturnType == typeof(int))
|
||||
// return Expression.Lambda<Func<T, int>>(block, instanceExpression);
|
||||
//if (methodReturnType == typeof(bool))
|
||||
// return Expression.Lambda<Func<T, bool>>(block, instanceExpression);
|
||||
//if (methodReturnType == typeof(string[]))
|
||||
//return Expression.Lambda<Func<T, string[]>>(block, instanceExpression);
|
||||
|
||||
//return Expression.Call(instance, (MethodInfo)method, args);
|
||||
|
||||
//return Expression.Lambda<Func<T, object>>(
|
||||
// Expression.Convert(block, typeof(object)), instanceExpression);
|
||||
|
||||
}
|
||||
|
||||
static Type FindGenericType(Type generic, Type type)
|
||||
@@ -1095,8 +1113,8 @@ namespace Umbraco.Web.Dynamics
|
||||
Expression.Return(cblockReturnLabel, cresult),
|
||||
Expression.Label(cblockReturnLabel, Expression.Constant(null, typeof(string))));
|
||||
|
||||
LambdaExpression lax2 = Expression.Lambda<Func<DynamicPublishedContent, string>>(cblock, instanceExpression);
|
||||
var expression = Expression.Lambda<Func<DynamicPublishedContent, string>>(cblock, instanceExpression);
|
||||
LambdaExpression lax2 = Expression.Lambda<Func<T, string>>(cblock, instanceExpression);
|
||||
var expression = Expression.Lambda<Func<T, string>>(cblock, instanceExpression);
|
||||
return expression;
|
||||
|
||||
}
|
||||
@@ -1398,7 +1416,23 @@ namespace Umbraco.Web.Dynamics
|
||||
{
|
||||
ParameterInfo pi = method.Parameters[i];
|
||||
if (pi.IsOut) return false;
|
||||
Expression promoted = PromoteExpression(args[i], pi.ParameterType, false);
|
||||
Expression promoted;
|
||||
|
||||
//TODO: Turns out this is real difficult to parse and don't really have time to figure this out at the moment
|
||||
// to parse params parameter arrays.
|
||||
|
||||
////here we need to check if it is a params array parameter
|
||||
//if (pi.ParameterType.IsArray
|
||||
// && pi.ParameterType.GetElementType() != null
|
||||
// && pi.GetCustomAttributes(typeof(ParamArrayAttribute), false).Any())
|
||||
//{
|
||||
// //it is a params parameter so convert the value to an array
|
||||
// promoted = PromoteExpression(args[i], pi.ParameterType.GetElementType(), false);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
promoted = PromoteExpression(args[i], pi.ParameterType, false);
|
||||
//}
|
||||
if (promoted == null) return false;
|
||||
promotedArgs[i] = promoted;
|
||||
}
|
||||
@@ -1413,7 +1447,7 @@ namespace Umbraco.Web.Dynamics
|
||||
//if the type of the expression is a func<DynamicNode, object> - invokable returning object,
|
||||
//we are going to return it here, because we can get the real value when we actually have the instance
|
||||
//if (typeof(Func<DynamicNode, object>).IsAssignableFrom(expr.Type)) return expr;
|
||||
if (expr is LambdaExpression && ((LambdaExpression)expr).Parameters.Count > 0 && ((LambdaExpression)expr).Parameters[0].Type == typeof(DynamicPublishedContent))
|
||||
if (expr is LambdaExpression && ((LambdaExpression)expr).Parameters.Count > 0 && ((LambdaExpression)expr).Parameters[0].Type == typeof(T))
|
||||
{
|
||||
return expr;
|
||||
}
|
||||
@@ -1692,12 +1726,12 @@ namespace Umbraco.Web.Dynamics
|
||||
UnaryExpression unboxedLeft = null, unboxedRight = null;
|
||||
ParameterExpression[] parameters = null;
|
||||
|
||||
if (left is LambdaExpression && (left as LambdaExpression).Type.GetGenericArguments().First() == typeof(DynamicPublishedContent))
|
||||
if (left is LambdaExpression && (left as LambdaExpression).Type.GetGenericArguments().First() == typeof(T))
|
||||
{
|
||||
leftIsLambda = true;
|
||||
}
|
||||
|
||||
if (right is LambdaExpression && (right as LambdaExpression).Type.GetGenericArguments().First() == typeof(DynamicPublishedContent))
|
||||
if (right is LambdaExpression && (right as LambdaExpression).Type.GetGenericArguments().First() == typeof(T))
|
||||
{
|
||||
rightIsLambda = true;
|
||||
}
|
||||
@@ -1751,11 +1785,11 @@ namespace Umbraco.Web.Dynamics
|
||||
|
||||
if (expressionType == ExpressionType.AndAlso)
|
||||
{
|
||||
return ExpressionExtensions.And<DynamicPublishedContent>(left as Expression<Func<DynamicPublishedContent, bool>>, right as Expression<Func<DynamicPublishedContent, bool>>);
|
||||
return ExpressionExtensions.And<T>(left as Expression<Func<T, bool>>, right as Expression<Func<T, bool>>);
|
||||
}
|
||||
if (expressionType == ExpressionType.OrElse)
|
||||
{
|
||||
return ExpressionExtensions.Or<DynamicPublishedContent>(left as Expression<Func<DynamicPublishedContent, bool>>, right as Expression<Func<DynamicPublishedContent, bool>>);
|
||||
return ExpressionExtensions.Or<T>(left as Expression<Func<T, bool>>, right as Expression<Func<T, bool>>);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1786,11 +1820,11 @@ namespace Umbraco.Web.Dynamics
|
||||
//left is invoked and unboxed to right's TOut, right was not boxed
|
||||
if (expressionType == ExpressionType.AndAlso)
|
||||
{
|
||||
return ExpressionExtensions.And<DynamicPublishedContent>(right as Expression<Func<DynamicPublishedContent, bool>>, Expression.Lambda<Func<DynamicPublishedContent, bool>>(unboxedLeft, parameters) as Expression<Func<DynamicPublishedContent, bool>>);
|
||||
return ExpressionExtensions.And<T>(right as Expression<Func<T, bool>>, Expression.Lambda<Func<T, bool>>(unboxedLeft, parameters) as Expression<Func<T, bool>>);
|
||||
}
|
||||
if (expressionType == ExpressionType.OrElse)
|
||||
{
|
||||
return ExpressionExtensions.And<DynamicPublishedContent>(right as Expression<Func<DynamicPublishedContent, bool>>, Expression.Lambda<Func<DynamicPublishedContent, bool>>(unboxedLeft, parameters) as Expression<Func<DynamicPublishedContent, bool>>);
|
||||
return ExpressionExtensions.And<T>(right as Expression<Func<T, bool>>, Expression.Lambda<Func<T, bool>>(unboxedLeft, parameters) as Expression<Func<T, bool>>);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1807,11 +1841,11 @@ namespace Umbraco.Web.Dynamics
|
||||
//right is invoked and unboxed to left's TOut, left was not boxed
|
||||
if (expressionType == ExpressionType.AndAlso)
|
||||
{
|
||||
return ExpressionExtensions.And<DynamicPublishedContent>(left as Expression<Func<DynamicPublishedContent, bool>>, Expression.Lambda<Func<DynamicPublishedContent, bool>>(unboxedRight, parameters) as Expression<Func<DynamicPublishedContent, bool>>);
|
||||
return ExpressionExtensions.And<T>(left as Expression<Func<T, bool>>, Expression.Lambda<Func<T, bool>>(unboxedRight, parameters) as Expression<Func<T, bool>>);
|
||||
}
|
||||
if (expressionType == ExpressionType.OrElse)
|
||||
{
|
||||
return ExpressionExtensions.And<DynamicPublishedContent>(left as Expression<Func<DynamicPublishedContent, bool>>, Expression.Lambda<Func<DynamicPublishedContent, bool>>(unboxedRight, parameters) as Expression<Func<DynamicPublishedContent, bool>>);
|
||||
return ExpressionExtensions.And<T>(left as Expression<Func<T, bool>>, Expression.Lambda<Func<T, bool>>(unboxedRight, parameters) as Expression<Func<T, bool>>);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1882,7 +1916,7 @@ namespace Umbraco.Web.Dynamics
|
||||
break;
|
||||
case ExpressionType.Modulo:
|
||||
binaryExpression = Expression.Modulo(finalLeft, finalRight);
|
||||
return (Expression.Lambda<Func<DynamicPublishedContent, int>>(binaryExpression, parameters));
|
||||
return (Expression.Lambda<Func<T, int>>(binaryExpression, parameters));
|
||||
case ExpressionType.AndAlso:
|
||||
if ((leftIsLambda && rightIsLambda && sequenceEqual) || (!leftIsLambda && !rightIsLambda))
|
||||
{
|
||||
@@ -1890,7 +1924,7 @@ namespace Umbraco.Web.Dynamics
|
||||
}
|
||||
else
|
||||
{
|
||||
return (Expression.Lambda<Func<DynamicPublishedContent, Boolean>>(Expression.AndAlso(finalLeft, finalRight), parameters));
|
||||
return (Expression.Lambda<Func<T, Boolean>>(Expression.AndAlso(finalLeft, finalRight), parameters));
|
||||
}
|
||||
case ExpressionType.OrElse:
|
||||
if (leftIsLambda && rightIsLambda && sequenceEqual || (!leftIsLambda && !rightIsLambda))
|
||||
@@ -1899,7 +1933,7 @@ namespace Umbraco.Web.Dynamics
|
||||
}
|
||||
else
|
||||
{
|
||||
return (Expression.Lambda<Func<DynamicPublishedContent, Boolean>>(Expression.OrElse(finalLeft, finalRight), parameters));
|
||||
return (Expression.Lambda<Func<T, Boolean>>(Expression.OrElse(finalLeft, finalRight), parameters));
|
||||
}
|
||||
default:
|
||||
return Expression.Equal(left, right);
|
||||
@@ -1907,7 +1941,7 @@ namespace Umbraco.Web.Dynamics
|
||||
if (leftIsLambda || rightIsLambda)
|
||||
{
|
||||
var body = Expression.Condition(Expression.TypeEqual(innerLeft, right.Type), binaryExpression, Expression.Constant(false));
|
||||
return Expression.Lambda<Func<DynamicPublishedContent, bool>>(body, parameters);
|
||||
return Expression.Lambda<Func<T, bool>>(body, parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -884,6 +884,12 @@ namespace Umbraco.Web.Models
|
||||
#endregion
|
||||
|
||||
#region Is Helpers
|
||||
|
||||
public bool IsDocumentType(string docTypeAlias)
|
||||
{
|
||||
return this.PublishedContent.IsDocumentType(docTypeAlias);
|
||||
}
|
||||
|
||||
public bool IsNull(string alias, bool recursive)
|
||||
{
|
||||
return this.PublishedContent.IsNull(alias, recursive);
|
||||
|
||||
@@ -54,10 +54,74 @@ namespace Umbraco.Web.Models
|
||||
//NOTE: For many of these we could actually leave them out since we are executing custom extension methods and because
|
||||
// we implement IEnumerable<T> they will execute just fine, however, to do that will be quite a bit slower than checking here.
|
||||
|
||||
var firstArg = args.FirstOrDefault();
|
||||
//this is to check for 'DocumentTypeAlias' vs 'NodeTypeAlias' for compatibility
|
||||
if (firstArg != null && firstArg.ToString().InvariantStartsWith("NodeTypeAlias"))
|
||||
{
|
||||
firstArg = "DocumentTypeAlias" + firstArg.ToString().Substring("NodeTypeAlias".Length);
|
||||
}
|
||||
|
||||
var name = binder.Name;
|
||||
if (name == "Single")
|
||||
{
|
||||
string predicate = firstArg == null ? "" : firstArg.ToString();
|
||||
var values = predicate.IsNullOrWhiteSpace() ? new object[] {} : args.Skip(1).ToArray();
|
||||
var single = this.Single<DynamicPublishedContent>(predicate, values);
|
||||
result = new DynamicPublishedContent(single);
|
||||
return true;
|
||||
}
|
||||
if (name == "SingleOrDefault")
|
||||
{
|
||||
string predicate = firstArg == null ? "" : firstArg.ToString();
|
||||
var values = predicate.IsNullOrWhiteSpace() ? new object[] { } : args.Skip(1).ToArray();
|
||||
var single = this.SingleOrDefault<DynamicPublishedContent>(predicate, values);
|
||||
if (single == null)
|
||||
result = new DynamicNull();
|
||||
else
|
||||
result = new DynamicPublishedContent(single);
|
||||
return true;
|
||||
}
|
||||
if (name == "First")
|
||||
{
|
||||
string predicate = firstArg == null ? "" : firstArg.ToString();
|
||||
var values = predicate.IsNullOrWhiteSpace() ? new object[] { } : args.Skip(1).ToArray();
|
||||
var first = this.First<DynamicPublishedContent>(predicate, values);
|
||||
result = new DynamicPublishedContent(first);
|
||||
return true;
|
||||
}
|
||||
if (name == "FirstOrDefault")
|
||||
{
|
||||
string predicate = firstArg == null ? "" : firstArg.ToString();
|
||||
var values = predicate.IsNullOrWhiteSpace() ? new object[] { } : args.Skip(1).ToArray();
|
||||
var first = this.FirstOrDefault<DynamicPublishedContent>(predicate, values);
|
||||
if (first == null)
|
||||
result = new DynamicNull();
|
||||
else
|
||||
result = new DynamicPublishedContent(first);
|
||||
return true;
|
||||
}
|
||||
if (name == "Last")
|
||||
{
|
||||
string predicate = firstArg == null ? "" : firstArg.ToString();
|
||||
var values = predicate.IsNullOrWhiteSpace() ? new object[] { } : args.Skip(1).ToArray();
|
||||
var last = this.Last<DynamicPublishedContent>(predicate, values);
|
||||
result = new DynamicPublishedContent(last);
|
||||
return true;
|
||||
}
|
||||
if (name == "LastOrDefault")
|
||||
{
|
||||
string predicate = firstArg == null ? "" : firstArg.ToString();
|
||||
var values = predicate.IsNullOrWhiteSpace() ? new object[] { } : args.Skip(1).ToArray();
|
||||
var last = this.LastOrDefault<DynamicPublishedContent>(predicate, values);
|
||||
if (last == null)
|
||||
result = new DynamicNull();
|
||||
else
|
||||
result = new DynamicPublishedContent(last);
|
||||
return true;
|
||||
}
|
||||
if (name == "Where")
|
||||
{
|
||||
string predicate = args.First().ToString();
|
||||
string predicate = firstArg.ToString();
|
||||
var values = args.Skip(1).ToArray();
|
||||
//TODO: We are pre-resolving the where into a ToList() here which will have performance impacts if there where clauses
|
||||
// are nested! We should somehow support an QueryableDocumentList!
|
||||
@@ -68,23 +132,23 @@ namespace Umbraco.Web.Models
|
||||
{
|
||||
//TODO: We are pre-resolving the where into a ToList() here which will have performance impacts if there where clauses
|
||||
// are nested! We should somehow support an QueryableDocumentList!
|
||||
result = new DynamicPublishedContentList(this.OrderBy<DynamicPublishedContent>(args.First().ToString()).ToList());
|
||||
result = new DynamicPublishedContentList(this.OrderBy<DynamicPublishedContent>(firstArg.ToString()).ToList());
|
||||
return true;
|
||||
}
|
||||
if (name == "Take")
|
||||
{
|
||||
result = new DynamicPublishedContentList(this.Take((int)args.First()));
|
||||
result = new DynamicPublishedContentList(this.Take((int)firstArg));
|
||||
return true;
|
||||
}
|
||||
if (name == "Skip")
|
||||
{
|
||||
result = new DynamicPublishedContentList(this.Skip((int)args.First()));
|
||||
result = new DynamicPublishedContentList(this.Skip((int)firstArg));
|
||||
return true;
|
||||
}
|
||||
if (name == "InGroupsOf")
|
||||
{
|
||||
int groupSize = 0;
|
||||
if (int.TryParse(args.First().ToString(), out groupSize))
|
||||
if (int.TryParse(firstArg.ToString(), out groupSize))
|
||||
{
|
||||
result = InGroupsOf(groupSize);
|
||||
return true;
|
||||
@@ -95,7 +159,7 @@ namespace Umbraco.Web.Models
|
||||
if (name == "GroupedInto")
|
||||
{
|
||||
int groupCount = 0;
|
||||
if (int.TryParse(args.First().ToString(), out groupCount))
|
||||
if (int.TryParse(firstArg.ToString(), out groupCount))
|
||||
{
|
||||
result = GroupedInto(groupCount);
|
||||
return true;
|
||||
@@ -105,7 +169,7 @@ namespace Umbraco.Web.Models
|
||||
}
|
||||
if (name == "GroupBy")
|
||||
{
|
||||
result = GroupBy(args.First().ToString());
|
||||
result = GroupBy(firstArg.ToString());
|
||||
return true;
|
||||
}
|
||||
if (name == "Average" || name == "Min" || name == "Max" || name == "Sum")
|
||||
@@ -115,40 +179,40 @@ namespace Umbraco.Web.Models
|
||||
}
|
||||
if (name == "Union")
|
||||
{
|
||||
if ((args.First() as IEnumerable<DynamicPublishedContent>) != null)
|
||||
if ((firstArg as IEnumerable<DynamicPublishedContent>) != null)
|
||||
{
|
||||
result = new DynamicPublishedContentList(this.Items.Union(args.First() as IEnumerable<DynamicPublishedContent>));
|
||||
result = new DynamicPublishedContentList(this.Items.Union(firstArg as IEnumerable<DynamicPublishedContent>));
|
||||
return true;
|
||||
}
|
||||
if ((args.First() as DynamicPublishedContentList) != null)
|
||||
if ((firstArg as DynamicPublishedContentList) != null)
|
||||
{
|
||||
result = new DynamicPublishedContentList(this.Items.Union((args.First() as DynamicPublishedContentList).Items));
|
||||
result = new DynamicPublishedContentList(this.Items.Union((firstArg as DynamicPublishedContentList).Items));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (name == "Except")
|
||||
{
|
||||
if ((args.First() as IEnumerable<DynamicPublishedContent>) != null)
|
||||
if ((firstArg as IEnumerable<DynamicPublishedContent>) != null)
|
||||
{
|
||||
result = new DynamicPublishedContentList(this.Items.Except(args.First() as IEnumerable<DynamicPublishedContent>, new DynamicPublishedContentIdEqualityComparer()));
|
||||
result = new DynamicPublishedContentList(this.Items.Except(firstArg as IEnumerable<DynamicPublishedContent>, new DynamicPublishedContentIdEqualityComparer()));
|
||||
return true;
|
||||
}
|
||||
if ((args.First() as DynamicPublishedContentList) != null)
|
||||
if ((firstArg as DynamicPublishedContentList) != null)
|
||||
{
|
||||
result = new DynamicPublishedContentList(this.Items.Except((args.First() as DynamicPublishedContentList).Items, new DynamicPublishedContentIdEqualityComparer()));
|
||||
result = new DynamicPublishedContentList(this.Items.Except((firstArg as DynamicPublishedContentList).Items, new DynamicPublishedContentIdEqualityComparer()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (name == "Intersect")
|
||||
{
|
||||
if ((args.First() as IEnumerable<DynamicPublishedContent>) != null)
|
||||
if ((firstArg as IEnumerable<DynamicPublishedContent>) != null)
|
||||
{
|
||||
result = new DynamicPublishedContentList(this.Items.Intersect(args.First() as IEnumerable<DynamicPublishedContent>, new DynamicPublishedContentIdEqualityComparer()));
|
||||
result = new DynamicPublishedContentList(this.Items.Intersect(firstArg as IEnumerable<DynamicPublishedContent>, new DynamicPublishedContentIdEqualityComparer()));
|
||||
return true;
|
||||
}
|
||||
if ((args.First() as DynamicPublishedContentList) != null)
|
||||
if ((firstArg as DynamicPublishedContentList) != null)
|
||||
{
|
||||
result = new DynamicPublishedContentList(this.Items.Intersect((args.First() as DynamicPublishedContentList).Items, new DynamicPublishedContentIdEqualityComparer()));
|
||||
result = new DynamicPublishedContentList(this.Items.Intersect((firstArg as DynamicPublishedContentList).Items, new DynamicPublishedContentIdEqualityComparer()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -422,13 +486,50 @@ namespace Umbraco.Web.Models
|
||||
return result;
|
||||
}
|
||||
|
||||
public T Single<T>(string predicate, params object[] values)
|
||||
{
|
||||
return predicate.IsNullOrWhiteSpace()
|
||||
? ((IQueryable<T>) Items.AsQueryable()).Single()
|
||||
: Where<T>(predicate, values).Single();
|
||||
}
|
||||
|
||||
public T SingleOrDefault<T>(string predicate, params object[] values)
|
||||
{
|
||||
return predicate.IsNullOrWhiteSpace()
|
||||
? ((IQueryable<T>)Items.AsQueryable()).SingleOrDefault()
|
||||
: Where<T>(predicate, values).SingleOrDefault();
|
||||
}
|
||||
public T First<T>(string predicate, params object[] values)
|
||||
{
|
||||
return predicate.IsNullOrWhiteSpace()
|
||||
? ((IQueryable<T>)Items.AsQueryable()).First()
|
||||
: Where<T>(predicate, values).First();
|
||||
}
|
||||
public T FirstOrDefault<T>(string predicate, params object[] values)
|
||||
{
|
||||
return predicate.IsNullOrWhiteSpace()
|
||||
? ((IQueryable<T>)Items.AsQueryable()).FirstOrDefault()
|
||||
: Where<T>(predicate, values).FirstOrDefault();
|
||||
}
|
||||
public T Last<T>(string predicate, params object[] values)
|
||||
{
|
||||
return predicate.IsNullOrWhiteSpace()
|
||||
? ((IQueryable<T>)Items.AsQueryable()).Last()
|
||||
: Where<T>(predicate, values).Last();
|
||||
}
|
||||
public T LastOrDefault<T>(string predicate, params object[] values)
|
||||
{
|
||||
return predicate.IsNullOrWhiteSpace()
|
||||
? ((IQueryable<T>)Items.AsQueryable()).LastOrDefault()
|
||||
: Where<T>(predicate, values).LastOrDefault();
|
||||
}
|
||||
public IQueryable<T> Where<T>(string predicate, params object[] values)
|
||||
{
|
||||
return ((IQueryable<T>)Items.AsQueryable()).Where(predicate, values);
|
||||
}
|
||||
public IQueryable<T> OrderBy<T>(string key)
|
||||
{
|
||||
return ((IQueryable<T>)Items.AsQueryable()).OrderBy(key);
|
||||
return ((IQueryable<T>)Items.AsQueryable()).OrderBy<T>(key, () => typeof(DynamicPublishedContentListOrdering));
|
||||
}
|
||||
public DynamicGrouping GroupBy(string key)
|
||||
{
|
||||
|
||||
@@ -131,6 +131,11 @@ namespace Umbraco.Web
|
||||
|
||||
#region Is Helpers
|
||||
|
||||
public static bool IsDocumentType(this IPublishedContent content, string docTypeAlias)
|
||||
{
|
||||
return content.DocumentTypeAlias == docTypeAlias;
|
||||
}
|
||||
|
||||
public static bool IsNull(this IPublishedContent content, string alias, bool recursive)
|
||||
{
|
||||
var prop = content.GetProperty(alias, recursive);
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Web.Templates
|
||||
public static string ParseInternalLinks(string text)
|
||||
{
|
||||
//don't attempt to proceed without a context as we cannot lookup urls without one
|
||||
if (UmbracoContext.Current == null)
|
||||
if (UmbracoContext.Current == null || UmbracoContext.Current.RoutingContext == null)
|
||||
{
|
||||
return text;
|
||||
}
|
||||
|
||||
@@ -89,7 +89,8 @@ namespace umbraco.presentation.install
|
||||
InstallerStep _s;
|
||||
|
||||
//if this is not an upgrade we will log in with the default user.
|
||||
if (!String.IsNullOrEmpty(GlobalSettings.ConfigurationStatus.Trim()))
|
||||
// It's not considered an upgrade if the ConfigurationStatus is missing or empty.
|
||||
if (String.IsNullOrWhiteSpace(GlobalSettings.ConfigurationStatus) == false)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace umbraco.presentation.install.steps.Definitions
|
||||
|
||||
public override bool Completed()
|
||||
{
|
||||
if (!String.IsNullOrEmpty(GlobalSettings.ConfigurationStatus.Trim()))
|
||||
if (String.IsNullOrWhiteSpace(GlobalSettings.ConfigurationStatus) == false)
|
||||
return true;
|
||||
|
||||
if (InstalledPackage.GetAllInstalledPackages().Count > 0)
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
<div class="container">
|
||||
<p>
|
||||
<strong>2. Getting a database setup for umbraco.</strong><br />
|
||||
For first time users, we recommend you select "quick-and-simple file-based database".
|
||||
For first time users, we recommend you select "quick-and-simple embedded database".
|
||||
This will install an easy to use database, that does
|
||||
not require any additional software to use.<br />
|
||||
Alternatively, you can install Microsoft SQL Server, which will require a bit more
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace umbraco.presentation.install.steps
|
||||
}
|
||||
|
||||
|
||||
if (GlobalSettings.ConfigurationStatus.Trim() == "")
|
||||
if (String.IsNullOrWhiteSpace(GlobalSettings.ConfigurationStatus))
|
||||
BasePages.UmbracoEnsuredPage.doLogin(u);
|
||||
|
||||
Helper.RedirectToNextStep(this.Page);
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
</p>
|
||||
<p>
|
||||
As this is an upgrade, <strong>the wizard might skip steps</strong> that are only needed for new umbraco installations. It might also ask you questions you've already answered once. But do not worry,
|
||||
everything is in order. Click <strong>Lets get started</strong> below to begin your upgrade.
|
||||
everything is in order. Click <strong>Let's get started</strong> below to begin your upgrade.
|
||||
</p>
|
||||
<span class="enjoy">Enjoy!</span>
|
||||
</asp:PlaceHolder>
|
||||
@@ -43,7 +43,7 @@
|
||||
<!-- btn box -->
|
||||
<footer class="btn-box">
|
||||
<div class="t"> </div>
|
||||
<asp:LinkButton ID="btnNext" CssClass="btn btn-get" runat="server" OnClick="gotoNextStep"><span>Lets get started!</span></asp:LinkButton>
|
||||
<asp:LinkButton ID="btnNext" CssClass="btn btn-get" runat="server" OnClick="gotoNextStep"><span>Let's get started!</span></asp:LinkButton>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
@@ -17,8 +17,8 @@ namespace umbraco.presentation.install
|
||||
|
||||
protected void Page_Load(object sender, System.EventArgs e)
|
||||
{
|
||||
|
||||
if (!String.IsNullOrEmpty(GlobalSettings.ConfigurationStatus.Trim()))
|
||||
// Display the Umbraco upgrade message if Umbraco is already installed
|
||||
if (String.IsNullOrWhiteSpace(GlobalSettings.ConfigurationStatus) == false)
|
||||
{
|
||||
ph_install.Visible = false;
|
||||
ph_upgrade.Visible = true;
|
||||
|
||||
@@ -36,12 +36,7 @@ namespace umbraco
|
||||
|
||||
protected override void CreateRootNode(ref XmlTreeNode rootNode)
|
||||
{
|
||||
if (!Umbraco.Core.Configuration.UmbracoSettings.EnableMvcSupport)
|
||||
rootNode.NodeType = "init" + TreeAlias;
|
||||
else
|
||||
rootNode.NodeType = "initviews";
|
||||
|
||||
|
||||
rootNode.NodeType = "init" + TreeAlias;
|
||||
rootNode.NodeID = "init";
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,13 @@
|
||||
<strong id="username"><%=umbraco.BusinessLogic.User.GetCurrent().Name%></strong>
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span>
|
||||
<asp:Label runat="server" AssociatedControlID="currentpassword" ID="Label2"><%=umbraco.ui.Text("password") %>:</asp:Label>
|
||||
<asp:TextBox id="currentpassword" TextMode="password" CssClass="textfield" Runat="server"></asp:TextBox>
|
||||
<asp:RequiredFieldValidator runat="server" ControlToValidate="currentpassword" ID="RequiredFieldValidator1" ValidationGroup="changepass">*</asp:RequiredFieldValidator>
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span>
|
||||
<asp:Label runat="server" AssociatedControlID="password" ID="passwordLabel"><%=umbraco.ui.Text("passwordEnterNew") %>:</asp:Label>
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace umbraco.presentation.umbraco.dashboard
|
||||
if (tempPassword == confirmpassword.Text)
|
||||
{
|
||||
// make sure password is not empty
|
||||
user.ChangePassword(u.Password, tempPassword);
|
||||
user.ChangePassword(currentpassword.Text, tempPassword);
|
||||
changeForm.Visible = false;
|
||||
errorPane.Visible = false;
|
||||
passwordChanged.Visible = true;
|
||||
|
||||
@@ -12,15 +12,6 @@ namespace umbraco.presentation.umbraco.dashboard {
|
||||
|
||||
public partial class ChangePassword {
|
||||
|
||||
/// <summary>
|
||||
/// changeForm control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.Panel changeForm;
|
||||
|
||||
/// <summary>
|
||||
/// JsInclude2 control.
|
||||
/// </summary>
|
||||
@@ -30,6 +21,15 @@ namespace umbraco.presentation.umbraco.dashboard {
|
||||
/// </remarks>
|
||||
protected global::ClientDependency.Core.Controls.JsInclude JsInclude2;
|
||||
|
||||
/// <summary>
|
||||
/// changeForm control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.Panel changeForm;
|
||||
|
||||
/// <summary>
|
||||
/// errorPane control.
|
||||
/// </summary>
|
||||
@@ -57,6 +57,33 @@ namespace umbraco.presentation.umbraco.dashboard {
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.Label Label1;
|
||||
|
||||
/// <summary>
|
||||
/// Label2 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.Label Label2;
|
||||
|
||||
/// <summary>
|
||||
/// currentpassword control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.TextBox currentpassword;
|
||||
|
||||
/// <summary>
|
||||
/// RequiredFieldValidator1 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidator1;
|
||||
|
||||
/// <summary>
|
||||
/// passwordLabel control.
|
||||
/// </summary>
|
||||
|
||||
@@ -136,9 +136,6 @@
|
||||
<HeaderTemplate>
|
||||
<table cellspacing="0" cellpadding="2" width="98%" border="0">
|
||||
<tr>
|
||||
<td class="propertyHeader">
|
||||
<%=umbraco.ui.Text("show",this.getUser())%>
|
||||
</td>
|
||||
<td class="propertyHeader">
|
||||
<%=umbraco.ui.Text("general", "alias",this.getUser())%>
|
||||
</td>
|
||||
@@ -153,9 +150,6 @@
|
||||
</HeaderTemplate>
|
||||
<ItemTemplate>
|
||||
<tr>
|
||||
<td class="propertyContent">
|
||||
<asp:CheckBox runat="server" ID="macroPropertyHidden" Checked='<%# macroIsVisible (DataBinder.Eval(Container.DataItem, "Public"))%>' />
|
||||
</td>
|
||||
<td class="propertyContent">
|
||||
<input type="hidden" id="macroPropertyID" runat="server" value='<%#DataBinder.Eval(Container.DataItem, "id")%>'
|
||||
name="macroPropertyID" />
|
||||
@@ -178,9 +172,6 @@
|
||||
</ItemTemplate>
|
||||
<FooterTemplate>
|
||||
<tr>
|
||||
<td class="propertyContent">
|
||||
<asp:CheckBox runat="server" ID="macroPropertyHiddenNew" />
|
||||
</td>
|
||||
<td class="propertyContent">
|
||||
<asp:TextBox runat="server" ID="macroPropertyAliasNew" Text='New Alias' OnTextChanged="macroPropertyCreate" />
|
||||
</td>
|
||||
|
||||
@@ -136,7 +136,6 @@ namespace umbraco.cms.presentation.developer
|
||||
DropDownList macroElementType = (DropDownList)item.FindControl("macroPropertyType");
|
||||
|
||||
MacroProperty mp = new MacroProperty(int.Parse(macroPropertyID.Value));
|
||||
mp.Public = macroElementShow.Checked;
|
||||
mp.Type = new MacroPropertyType(int.Parse(macroElementType.SelectedValue));
|
||||
mp.Alias = macroElementAlias.Text;
|
||||
mp.Name = macroElementName.Text;
|
||||
@@ -253,7 +252,6 @@ namespace umbraco.cms.presentation.developer
|
||||
|
||||
public void macroPropertyCreate(object sender, EventArgs e)
|
||||
{
|
||||
CheckBox macroPropertyHiddenNew = (CheckBox)((Control)sender).Parent.FindControl("macroPropertyHiddenNew");
|
||||
TextBox macroPropertyAliasNew = (TextBox)((Control)sender).Parent.FindControl("macroPropertyAliasNew");
|
||||
TextBox macroPropertyNameNew = (TextBox)((Control)sender).Parent.FindControl("macroPropertyNameNew");
|
||||
DropDownList macroPropertyTypeNew = (DropDownList)((Control)sender).Parent.FindControl("macroPropertyTypeNew");
|
||||
@@ -277,7 +275,7 @@ namespace umbraco.cms.presentation.developer
|
||||
{
|
||||
MacroProperty mp = new MacroProperty();
|
||||
mp.Macro = m_macro;
|
||||
mp.Public = macroPropertyHiddenNew.Checked;
|
||||
mp.Public = true;
|
||||
mp.Type = new MacroPropertyType(int.Parse(macroPropertyTypeNew.SelectedValue));
|
||||
mp.Alias = macroPropertyAliasNew.Text;
|
||||
mp.Name = macroPropertyNameNew.Text;
|
||||
|
||||
@@ -50,19 +50,7 @@ namespace umbraco.cms.presentation.settings
|
||||
if (t.Id != _template.Id)
|
||||
{
|
||||
var li = new ListItem(t.Text, t.Id.ToString());
|
||||
|
||||
li.Attributes.Add("id", t.Alias.Replace(" ", ""));
|
||||
|
||||
if (t.Id == _template.MasterTemplate)
|
||||
{
|
||||
try
|
||||
{
|
||||
li.Selected = true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
MasterTemplate.Items.Add(li);
|
||||
}
|
||||
}
|
||||
@@ -71,6 +59,14 @@ namespace umbraco.cms.presentation.settings
|
||||
AliasTxt.Text = _template.Alias;
|
||||
editorSource.Text = _template.Design;
|
||||
|
||||
try
|
||||
{
|
||||
if (_template.MasterTemplate > 0)
|
||||
MasterTemplate.SelectedValue = _template.MasterTemplate.ToString();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
}
|
||||
|
||||
ClientTools
|
||||
.SetActiveTreeType(TreeDefinitionCollection.Instance.FindTree<loadTemplates>().Tree.Alias)
|
||||
|
||||
@@ -129,6 +129,24 @@ namespace umbraco.presentation.webservices
|
||||
return new cms.businesslogic.CMSNode(nodeId).Text;
|
||||
}
|
||||
|
||||
[WebMethod]
|
||||
[ScriptMethod]
|
||||
public string[] GetNodeBreadcrumbs(int nodeId)
|
||||
{
|
||||
|
||||
Authorize();
|
||||
|
||||
var node = new cms.businesslogic.CMSNode(nodeId);
|
||||
var crumbs = new System.Collections.Generic.List<string>() { node.Text };
|
||||
while (node != null && node.Level > 1)
|
||||
{
|
||||
node = node.Parent;
|
||||
crumbs.Add(node.Text);
|
||||
}
|
||||
crumbs.Reverse();
|
||||
return crumbs.ToArray();
|
||||
}
|
||||
|
||||
[WebMethod]
|
||||
[ScriptMethod]
|
||||
public string NiceUrl(int nodeId)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using umbraco.MacroEngines;
|
||||
|
||||
namespace System.Linq.Dynamic
|
||||
{
|
||||
@@ -7,29 +8,27 @@ namespace System.Linq.Dynamic
|
||||
[Obsolete("This class has been superceded by Umbraco.Core.Dynamics.DynamicExpression")]
|
||||
public static class DynamicExpression
|
||||
{
|
||||
public static bool ConvertDynamicNullToBooleanFalse
|
||||
{
|
||||
get { return Umbraco.Web.Dynamics.DynamicExpression.ConvertDynamicNullToBooleanFalse; }
|
||||
set { Umbraco.Web.Dynamics.DynamicExpression.ConvertDynamicNullToBooleanFalse = value; }
|
||||
}
|
||||
[Obsolete("This property is no longer used and had caused concurrency issues.")]
|
||||
public static bool ConvertDynamicNullToBooleanFalse { get; set; }
|
||||
|
||||
public static Expression Parse(Type resultType, string expression, bool convertDynamicNullToBooleanFalse, params object[] values)
|
||||
{
|
||||
return Umbraco.Web.Dynamics.DynamicExpression.Parse(resultType, expression, convertDynamicNullToBooleanFalse, values);
|
||||
return Umbraco.Web.Dynamics.DynamicExpression.Parse<DynamicNode>(resultType, expression, convertDynamicNullToBooleanFalse, values);
|
||||
}
|
||||
|
||||
public static LambdaExpression ParseLambda(Type itType, Type resultType, string expression, bool convertDynamicNullToBooleanFalse, params object[] values)
|
||||
{
|
||||
return Umbraco.Web.Dynamics.DynamicExpression.ParseLambda(itType, resultType, expression, convertDynamicNullToBooleanFalse, values);
|
||||
return Umbraco.Web.Dynamics.DynamicExpression.ParseLambda<DynamicNode>(itType, resultType, expression, convertDynamicNullToBooleanFalse, values);
|
||||
}
|
||||
|
||||
public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type resultType, string expression, bool convertDynamicNullToBooleanFalse, params object[] values)
|
||||
{
|
||||
return Umbraco.Web.Dynamics.DynamicExpression.ParseLambda(parameters, resultType, expression, convertDynamicNullToBooleanFalse, values);
|
||||
return Umbraco.Web.Dynamics.DynamicExpression.ParseLambda<DynamicNode>(parameters, resultType, expression, convertDynamicNullToBooleanFalse, values);
|
||||
}
|
||||
|
||||
public static Expression<Func<T, S>> ParseLambda<T, S>(string expression, bool convertDynamicNullToBooleanFalse, params object[] values)
|
||||
{
|
||||
return Umbraco.Web.Dynamics.DynamicExpression.ParseLambda<T, S>(expression, convertDynamicNullToBooleanFalse, values);
|
||||
return Umbraco.Web.Dynamics.DynamicExpression.ParseLambda<DynamicNode, T, S>(expression, convertDynamicNullToBooleanFalse, values);
|
||||
}
|
||||
|
||||
public static Type CreateClass(params DynamicProperty[] properties)
|
||||
|
||||
@@ -6,7 +6,7 @@ using System.Collections;
|
||||
|
||||
namespace umbraco.MacroEngines
|
||||
{
|
||||
public class DynamicGrouping : IEnumerable
|
||||
public class DynamicGrouping : IEnumerable<IGrouping<object, DynamicNode>>, IEnumerable<Grouping<object, DynamicNode>>
|
||||
{
|
||||
public IEnumerable<Grouping<object, DynamicNode>> Inner;
|
||||
|
||||
@@ -45,7 +45,17 @@ namespace umbraco.MacroEngines
|
||||
this.Inner = source;
|
||||
}
|
||||
|
||||
public IEnumerator GetEnumerator()
|
||||
IEnumerator<Grouping<object, DynamicNode>> IEnumerable<Grouping<object, DynamicNode>>.GetEnumerator()
|
||||
{
|
||||
return Inner.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator<IGrouping<object, DynamicNode>> IEnumerable<IGrouping<object, DynamicNode>>.GetEnumerator()
|
||||
{
|
||||
return Inner.GetEnumerator();
|
||||
}
|
||||
|
||||
public IEnumerator GetEnumerator()
|
||||
{
|
||||
return Inner.GetEnumerator();
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ using Examine.LuceneEngine.SearchCriteria;
|
||||
|
||||
namespace umbraco.MacroEngines
|
||||
{
|
||||
public class DynamicNode : DynamicObject
|
||||
public class DynamicNode : DynamicObject, INode
|
||||
{
|
||||
/// <summary>
|
||||
/// This callback is used only so we can set it dynamically for use in unit tests
|
||||
@@ -1334,6 +1334,11 @@ namespace umbraco.MacroEngines
|
||||
}
|
||||
}
|
||||
|
||||
public DynamicNodeList Children
|
||||
{
|
||||
get { return ChildrenAsList; }
|
||||
}
|
||||
|
||||
public IProperty GetProperty(string alias)
|
||||
{
|
||||
if (n == null) return null;
|
||||
@@ -1773,5 +1778,129 @@ namespace umbraco.MacroEngines
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#region Explicit INode implementation
|
||||
INode INode.Parent
|
||||
{
|
||||
get { return Parent; }
|
||||
}
|
||||
|
||||
int INode.Id
|
||||
{
|
||||
get { return Id; }
|
||||
}
|
||||
|
||||
int INode.template
|
||||
{
|
||||
get { return template; }
|
||||
}
|
||||
|
||||
int INode.SortOrder
|
||||
{
|
||||
get { return SortOrder; }
|
||||
}
|
||||
|
||||
string INode.Name
|
||||
{
|
||||
get { return Name; }
|
||||
}
|
||||
|
||||
string INode.Url
|
||||
{
|
||||
get { return Url; }
|
||||
}
|
||||
|
||||
string INode.UrlName
|
||||
{
|
||||
get { return UrlName; }
|
||||
}
|
||||
|
||||
string INode.NodeTypeAlias
|
||||
{
|
||||
get { return NodeTypeAlias; }
|
||||
}
|
||||
|
||||
string INode.WriterName
|
||||
{
|
||||
get { return WriterName; }
|
||||
}
|
||||
|
||||
string INode.CreatorName
|
||||
{
|
||||
get { return CreatorName; }
|
||||
}
|
||||
|
||||
int INode.WriterID
|
||||
{
|
||||
get { return WriterID; }
|
||||
}
|
||||
|
||||
int INode.CreatorID
|
||||
{
|
||||
get { return CreatorID; }
|
||||
}
|
||||
|
||||
string INode.Path
|
||||
{
|
||||
get { return Path; }
|
||||
}
|
||||
|
||||
DateTime INode.CreateDate
|
||||
{
|
||||
get { return CreateDate; }
|
||||
}
|
||||
|
||||
DateTime INode.UpdateDate
|
||||
{
|
||||
get { return UpdateDate; }
|
||||
}
|
||||
|
||||
Guid INode.Version
|
||||
{
|
||||
get { return Version; }
|
||||
}
|
||||
|
||||
string INode.NiceUrl
|
||||
{
|
||||
get { return NiceUrl; }
|
||||
}
|
||||
|
||||
int INode.Level
|
||||
{
|
||||
get { return Level; }
|
||||
}
|
||||
|
||||
List<IProperty> INode.PropertiesAsList
|
||||
{
|
||||
get { return PropertiesAsList; }
|
||||
}
|
||||
|
||||
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, 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(string nodeTypeAliasFilter)
|
||||
{
|
||||
return ChildrenAsTable(nodeTypeAliasFilter);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ using System.Runtime.CompilerServices;
|
||||
using System.Web.Compilation;
|
||||
using System.Linq.Expressions;
|
||||
using System.Linq.Dynamic;
|
||||
using Umbraco.Core;
|
||||
namespace umbraco.MacroEngines
|
||||
{
|
||||
public class DynamicNodeList : DynamicObject, IEnumerable<DynamicNode>
|
||||
@@ -68,33 +69,97 @@ namespace umbraco.MacroEngines
|
||||
}
|
||||
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
|
||||
{
|
||||
var firstArg = args.FirstOrDefault();
|
||||
//this is to check for 'DocumentTypeAlias' vs 'NodeTypeAlias' for compatibility
|
||||
if (firstArg != null && firstArg.ToString().InvariantStartsWith("DocumentTypeAlias"))
|
||||
{
|
||||
firstArg = "NodeTypeAlias" + firstArg.ToString().Substring("DocumentTypeAlias".Length);
|
||||
}
|
||||
|
||||
var name = binder.Name;
|
||||
if (name == "Single")
|
||||
{
|
||||
string predicate = firstArg == null ? "" : firstArg.ToString();
|
||||
var values = predicate.IsNullOrWhiteSpace() ? new object[] { } : args.Skip(1).ToArray();
|
||||
var single = this.Single<DynamicNode>(predicate, values);
|
||||
result = new DynamicNode(single);
|
||||
return true;
|
||||
}
|
||||
if (name == "SingleOrDefault")
|
||||
{
|
||||
string predicate = firstArg == null ? "" : firstArg.ToString();
|
||||
var values = predicate.IsNullOrWhiteSpace() ? new object[] { } : args.Skip(1).ToArray();
|
||||
var single = this.SingleOrDefault<DynamicNode>(predicate, values);
|
||||
if (single == null)
|
||||
result = new DynamicNull();
|
||||
else
|
||||
result = new DynamicNode(single);
|
||||
return true;
|
||||
}
|
||||
if (name == "First")
|
||||
{
|
||||
string predicate = firstArg == null ? "" : firstArg.ToString();
|
||||
var values = predicate.IsNullOrWhiteSpace() ? new object[] { } : args.Skip(1).ToArray();
|
||||
var first = this.First<DynamicNode>(predicate, values);
|
||||
result = new DynamicNode(first);
|
||||
return true;
|
||||
}
|
||||
if (name == "FirstOrDefault")
|
||||
{
|
||||
string predicate = firstArg == null ? "" : firstArg.ToString();
|
||||
var values = predicate.IsNullOrWhiteSpace() ? new object[] { } : args.Skip(1).ToArray();
|
||||
var first = this.FirstOrDefault<DynamicNode>(predicate, values);
|
||||
if (first == null)
|
||||
result = new DynamicNull();
|
||||
else
|
||||
result = new DynamicNode(first);
|
||||
return true;
|
||||
}
|
||||
if (name == "Last")
|
||||
{
|
||||
string predicate = firstArg == null ? "" : firstArg.ToString();
|
||||
var values = predicate.IsNullOrWhiteSpace() ? new object[] { } : args.Skip(1).ToArray();
|
||||
var last = this.Last<DynamicNode>(predicate, values);
|
||||
result = new DynamicNode(last);
|
||||
return true;
|
||||
}
|
||||
if (name == "LastOrDefault")
|
||||
{
|
||||
string predicate = firstArg == null ? "" : firstArg.ToString();
|
||||
var values = predicate.IsNullOrWhiteSpace() ? new object[] { } : args.Skip(1).ToArray();
|
||||
var last = this.LastOrDefault<DynamicNode>(predicate, values);
|
||||
if (last == null)
|
||||
result = new DynamicNull();
|
||||
else
|
||||
result = new DynamicNode(last);
|
||||
return true;
|
||||
}
|
||||
if (name == "Where")
|
||||
{
|
||||
string predicate = args.First().ToString();
|
||||
string predicate = firstArg.ToString();
|
||||
var values = args.Skip(1).ToArray();
|
||||
result = new DynamicNodeList(this.Where<DynamicNode>(predicate, values).ToList());
|
||||
return true;
|
||||
}
|
||||
if (name == "OrderBy")
|
||||
{
|
||||
result = new DynamicNodeList(this.OrderBy<DynamicNode>(args.First().ToString()).ToList());
|
||||
result = new DynamicNodeList(this.OrderBy<DynamicNode>(firstArg.ToString()).ToList());
|
||||
return true;
|
||||
}
|
||||
if (name == "Take")
|
||||
{
|
||||
result = new DynamicNodeList(this.Take((int)args.First()));
|
||||
result = new DynamicNodeList(this.Take((int)firstArg));
|
||||
return true;
|
||||
}
|
||||
if (name == "Skip")
|
||||
{
|
||||
result = new DynamicNodeList(this.Skip((int)args.First()));
|
||||
result = new DynamicNodeList(this.Skip((int)firstArg));
|
||||
return true;
|
||||
}
|
||||
if (name == "InGroupsOf")
|
||||
{
|
||||
int groupSize = 0;
|
||||
if (int.TryParse(args.First().ToString(), out groupSize))
|
||||
if (int.TryParse(firstArg.ToString(), out groupSize))
|
||||
{
|
||||
result = this.InGroupsOf<DynamicNode>(groupSize);
|
||||
return true;
|
||||
@@ -105,7 +170,7 @@ namespace umbraco.MacroEngines
|
||||
if (name == "GroupedInto")
|
||||
{
|
||||
int groupCount = 0;
|
||||
if (int.TryParse(args.First().ToString(), out groupCount))
|
||||
if (int.TryParse(firstArg.ToString(), out groupCount))
|
||||
{
|
||||
result = this.GroupedInto<DynamicNode>(groupCount);
|
||||
return true;
|
||||
@@ -115,7 +180,7 @@ namespace umbraco.MacroEngines
|
||||
}
|
||||
if (name == "GroupBy")
|
||||
{
|
||||
result = this.GroupBy<DynamicNode>(args.First().ToString());
|
||||
result = this.GroupBy<DynamicNode>(firstArg.ToString());
|
||||
return true;
|
||||
}
|
||||
if (name == "Average" || name == "Min" || name == "Max" || name == "Sum")
|
||||
@@ -125,40 +190,40 @@ namespace umbraco.MacroEngines
|
||||
}
|
||||
if (name == "Union")
|
||||
{
|
||||
if ((args.First() as IEnumerable<DynamicNode>) != null)
|
||||
if ((firstArg as IEnumerable<DynamicNode>) != null)
|
||||
{
|
||||
result = new DynamicNodeList(this.Items.Union(args.First() as IEnumerable<DynamicNode>));
|
||||
result = new DynamicNodeList(this.Items.Union(firstArg as IEnumerable<DynamicNode>));
|
||||
return true;
|
||||
}
|
||||
if ((args.First() as DynamicNodeList) != null)
|
||||
if ((firstArg as DynamicNodeList) != null)
|
||||
{
|
||||
result = new DynamicNodeList(this.Items.Union((args.First() as DynamicNodeList).Items));
|
||||
result = new DynamicNodeList(this.Items.Union((firstArg as DynamicNodeList).Items));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (name == "Except")
|
||||
{
|
||||
if ((args.First() as IEnumerable<DynamicNode>) != null)
|
||||
if ((firstArg as IEnumerable<DynamicNode>) != null)
|
||||
{
|
||||
result = new DynamicNodeList(this.Items.Except(args.First() as IEnumerable<DynamicNode>, new DynamicNodeIdEqualityComparer()));
|
||||
result = new DynamicNodeList(this.Items.Except(firstArg as IEnumerable<DynamicNode>, new DynamicNodeIdEqualityComparer()));
|
||||
return true;
|
||||
}
|
||||
if ((args.First() as DynamicNodeList) != null)
|
||||
if ((firstArg as DynamicNodeList) != null)
|
||||
{
|
||||
result = new DynamicNodeList(this.Items.Except((args.First() as DynamicNodeList).Items, new DynamicNodeIdEqualityComparer()));
|
||||
result = new DynamicNodeList(this.Items.Except((firstArg as DynamicNodeList).Items, new DynamicNodeIdEqualityComparer()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (name == "Intersect")
|
||||
{
|
||||
if ((args.First() as IEnumerable<DynamicNode>) != null)
|
||||
if ((firstArg as IEnumerable<DynamicNode>) != null)
|
||||
{
|
||||
result = new DynamicNodeList(this.Items.Intersect(args.First() as IEnumerable<DynamicNode>, new DynamicNodeIdEqualityComparer()));
|
||||
result = new DynamicNodeList(this.Items.Intersect(firstArg as IEnumerable<DynamicNode>, new DynamicNodeIdEqualityComparer()));
|
||||
return true;
|
||||
}
|
||||
if ((args.First() as DynamicNodeList) != null)
|
||||
if ((firstArg as DynamicNodeList) != null)
|
||||
{
|
||||
result = new DynamicNodeList(this.Items.Intersect((args.First() as DynamicNodeList).Items, new DynamicNodeIdEqualityComparer()));
|
||||
result = new DynamicNodeList(this.Items.Intersect((firstArg as DynamicNodeList).Items, new DynamicNodeIdEqualityComparer()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -432,6 +497,42 @@ namespace umbraco.MacroEngines
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public T Single<T>(string predicate, params object[] values)
|
||||
{
|
||||
return predicate.IsNullOrWhiteSpace()
|
||||
? ((IQueryable<T>)Items.AsQueryable()).Single()
|
||||
: Where<T>(predicate, values).Single();
|
||||
}
|
||||
public T SingleOrDefault<T>(string predicate, params object[] values)
|
||||
{
|
||||
return predicate.IsNullOrWhiteSpace()
|
||||
? ((IQueryable<T>)Items.AsQueryable()).SingleOrDefault()
|
||||
: Where<T>(predicate, values).SingleOrDefault();
|
||||
}
|
||||
public T First<T>(string predicate, params object[] values)
|
||||
{
|
||||
return predicate.IsNullOrWhiteSpace()
|
||||
? ((IQueryable<T>)Items.AsQueryable()).First()
|
||||
: Where<T>(predicate, values).First();
|
||||
}
|
||||
public T FirstOrDefault<T>(string predicate, params object[] values)
|
||||
{
|
||||
return predicate.IsNullOrWhiteSpace()
|
||||
? ((IQueryable<T>)Items.AsQueryable()).FirstOrDefault()
|
||||
: Where<T>(predicate, values).FirstOrDefault();
|
||||
}
|
||||
public T Last<T>(string predicate, params object[] values)
|
||||
{
|
||||
return predicate.IsNullOrWhiteSpace()
|
||||
? ((IQueryable<T>)Items.AsQueryable()).Last()
|
||||
: Where<T>(predicate, values).Last();
|
||||
}
|
||||
public T LastOrDefault<T>(string predicate, params object[] values)
|
||||
{
|
||||
return predicate.IsNullOrWhiteSpace()
|
||||
? ((IQueryable<T>)Items.AsQueryable()).LastOrDefault()
|
||||
: Where<T>(predicate, values).LastOrDefault();
|
||||
}
|
||||
public IQueryable<T> Where<T>(string predicate, params object[] values)
|
||||
{
|
||||
return ((IQueryable<T>)Items.AsQueryable()).Where(predicate, values);
|
||||
|
||||
@@ -10,309 +10,58 @@ using System.Diagnostics;
|
||||
|
||||
namespace System.Linq.Dynamic
|
||||
{
|
||||
|
||||
|
||||
[Obsolete("This class has been superceded by Umbraco.Web.Dynamics.DynamicQueryable but is marked internal and shouldn't be used directly in your code")]
|
||||
public static class DynamicQueryable
|
||||
{
|
||||
public static IQueryable<T> Where<T>(this IQueryable<T> source, string predicate, params object[] values)
|
||||
{
|
||||
return (IQueryable<T>)Where((IQueryable)source, predicate, values);
|
||||
return (IQueryable<T>)Umbraco.Web.Dynamics.DynamicQueryable.Where<T>((IQueryable)source, predicate, values);
|
||||
}
|
||||
|
||||
public static IQueryable Where(this IQueryable source, string predicate, params object[] values)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
if (predicate == null) throw new ArgumentNullException("predicate");
|
||||
LambdaExpression lambda = Umbraco.Web.Dynamics.DynamicExpression.ParseLambda(source.ElementType, typeof(bool), predicate, true, values);
|
||||
if (lambda.Parameters.Count > 0 && lambda.Parameters[0].Type == typeof(DynamicNode))
|
||||
{
|
||||
//source list is DynamicNode and the lambda returns a Func<object>
|
||||
IQueryable<DynamicNode> typedSource = source as IQueryable<DynamicNode>;
|
||||
var compiledFunc = lambda.Compile();
|
||||
Func<DynamicNode, object> func = null;
|
||||
Func<DynamicNode, bool> boolFunc = null;
|
||||
if (compiledFunc is Func<DynamicNode, object>)
|
||||
{
|
||||
func = (Func<DynamicNode, object>)compiledFunc;
|
||||
}
|
||||
if (compiledFunc is Func<DynamicNode, bool>)
|
||||
{
|
||||
boolFunc = (Func<DynamicNode, bool>)compiledFunc;
|
||||
}
|
||||
return typedSource.Where(delegate(DynamicNode node)
|
||||
{
|
||||
object value = -1;
|
||||
//value = func(node);
|
||||
//I can't figure out why this is double func<>'d
|
||||
try
|
||||
{
|
||||
if (func != null)
|
||||
{
|
||||
var firstFuncResult = func(node);
|
||||
if (firstFuncResult is Func<DynamicNode, object>)
|
||||
{
|
||||
value = (firstFuncResult as Func<DynamicNode, object>)(node);
|
||||
}
|
||||
if (firstFuncResult is Func<DynamicNode, bool>)
|
||||
{
|
||||
value = (firstFuncResult as Func<DynamicNode, bool>)(node);
|
||||
}
|
||||
if (firstFuncResult is bool)
|
||||
{
|
||||
return (bool)firstFuncResult;
|
||||
}
|
||||
if (value is bool)
|
||||
{
|
||||
return (bool)value;
|
||||
}
|
||||
}
|
||||
if (boolFunc != null)
|
||||
{
|
||||
return boolFunc(node);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Trace.WriteLine(ex.Message);
|
||||
return false;
|
||||
}
|
||||
}).AsQueryable();
|
||||
}
|
||||
else
|
||||
{
|
||||
return source.Provider.CreateQuery(
|
||||
Expression.Call(
|
||||
typeof(Queryable), "Where",
|
||||
new Type[] { source.ElementType },
|
||||
source.Expression, Expression.Quote(lambda)));
|
||||
}
|
||||
return (IQueryable)Umbraco.Web.Dynamics.DynamicQueryable.Where<DynamicNode>((IQueryable)source, predicate, values);
|
||||
}
|
||||
|
||||
public static IQueryable Select(this IQueryable<DynamicNode> source, string selector, params object[] values)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
if (selector == null) throw new ArgumentNullException("selector");
|
||||
LambdaExpression lambda = Umbraco.Web.Dynamics.DynamicExpression.ParseLambda(source.ElementType, typeof(object), selector, false, values);
|
||||
if (lambda.Parameters.Count > 0 && lambda.Parameters[0].Type == typeof(DynamicNode))
|
||||
{
|
||||
//source list is DynamicNode and the lambda returns a Func<object>
|
||||
IQueryable<DynamicNode> typedSource = source as IQueryable<DynamicNode>;
|
||||
var compiledFunc = lambda.Compile();
|
||||
Func<DynamicNode, object> func = null;
|
||||
if (compiledFunc is Func<DynamicNode, object>)
|
||||
{
|
||||
func = (Func<DynamicNode, object>)compiledFunc;
|
||||
}
|
||||
return typedSource.Select(delegate(DynamicNode node)
|
||||
{
|
||||
object value = null;
|
||||
value = func(node);
|
||||
if (value is Func<DynamicNode, object>)
|
||||
{
|
||||
var innerValue = (value as Func<DynamicNode, object>)(node);
|
||||
return innerValue;
|
||||
}
|
||||
return value;
|
||||
}).AsQueryable();
|
||||
}
|
||||
else
|
||||
{
|
||||
return source.Provider.CreateQuery(
|
||||
Expression.Call(
|
||||
typeof(Queryable), "Select",
|
||||
new Type[] { source.ElementType, lambda.Body.Type },
|
||||
source.Expression, Expression.Quote(lambda)));
|
||||
}
|
||||
return (IQueryable)Umbraco.Web.Dynamics.DynamicQueryable.Select<DynamicNode>(source, selector, values);
|
||||
}
|
||||
|
||||
public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering, params object[] values)
|
||||
{
|
||||
return (IQueryable<T>)OrderBy((IQueryable)source, ordering, values);
|
||||
return (IQueryable<T>)Umbraco.Web.Dynamics.DynamicQueryable.OrderBy<T>(source, ordering, () => typeof(DynamicNodeListOrdering), values);
|
||||
}
|
||||
|
||||
public static IQueryable OrderBy(this IQueryable source, string ordering, params object[] values)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
if (ordering == null) throw new ArgumentNullException("ordering");
|
||||
|
||||
IQueryable<DynamicNode> typedSource = source as IQueryable<DynamicNode>;
|
||||
if (!ordering.Contains(","))
|
||||
{
|
||||
bool descending = false;
|
||||
if (ordering.IndexOf(" descending", StringComparison.CurrentCultureIgnoreCase) >= 0)
|
||||
{
|
||||
ordering = ordering.Replace(" descending", "");
|
||||
descending = true;
|
||||
}
|
||||
if (ordering.IndexOf(" desc", StringComparison.CurrentCultureIgnoreCase) >= 0)
|
||||
{
|
||||
ordering = ordering.Replace(" desc", "");
|
||||
descending = true;
|
||||
}
|
||||
|
||||
LambdaExpression lambda = Umbraco.Web.Dynamics.DynamicExpression.ParseLambda(source.ElementType, typeof(object), ordering, false, values);
|
||||
if (lambda.Parameters.Count > 0 && lambda.Parameters[0].Type == typeof(DynamicNode))
|
||||
{
|
||||
//source list is DynamicNode and the lambda returns a Func<object>
|
||||
Func<DynamicNode, object> func = (Func<DynamicNode, object>)lambda.Compile();
|
||||
//get the values out
|
||||
var query = typedSource.ToList().ConvertAll(item => new { node = item, key = EvaluateDynamicNodeFunc(item, func) });
|
||||
if (query.Count == 0)
|
||||
{
|
||||
return source;
|
||||
}
|
||||
var types = from i in query
|
||||
group i by i.key.GetType() into g
|
||||
where g.Key != typeof(DynamicNull)
|
||||
orderby g.Count() descending
|
||||
select new { g, Instances = g.Count() };
|
||||
var dominantType = types.First().g.Key;
|
||||
|
||||
// NH - add culture dependencies
|
||||
StringComparer comp = StringComparer.Create(CultureInfo.CurrentCulture, true);
|
||||
|
||||
if (!descending)
|
||||
{
|
||||
// if the dominant type is a string we'll ensure that strings are sorted based on culture settings on node
|
||||
if (dominantType.FullName == "System.String")
|
||||
return query.OrderBy(item => item.key.ToString(), comp).Select(item => item.node).AsQueryable();
|
||||
else
|
||||
return query.OrderBy(item => GetObjectAsTypeOrDefault(item.key, dominantType)).Select(item => item.node).AsQueryable();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dominantType.FullName == "System.String")
|
||||
return query.OrderByDescending(item => item.key.ToString(), comp).Select(item => item.node).AsQueryable();
|
||||
else
|
||||
return query.OrderByDescending(item => GetObjectAsTypeOrDefault(item.key, dominantType)).Select(item => item.node).AsQueryable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isDynamicNodeList = false;
|
||||
if (typedSource != null)
|
||||
{
|
||||
isDynamicNodeList = true;
|
||||
}
|
||||
|
||||
ParameterExpression[] parameters = new ParameterExpression[] {
|
||||
Expression.Parameter(source.ElementType, "") };
|
||||
ExpressionParser parser = new ExpressionParser(parameters, ordering, values);
|
||||
var orderings = parser.ParseOrdering();
|
||||
Expression queryExpr = source.Expression;
|
||||
string methodAsc = "OrderBy";
|
||||
string methodDesc = "OrderByDescending";
|
||||
foreach (var o in orderings)
|
||||
{
|
||||
if (!isDynamicNodeList)
|
||||
{
|
||||
queryExpr = Expression.Call(
|
||||
typeof(Queryable), o.Ascending ? methodAsc : methodDesc,
|
||||
new Type[] { source.ElementType, o.Selector.Type },
|
||||
queryExpr, Expression.Quote(Expression.Lambda(o.Selector, parameters)));
|
||||
}
|
||||
else
|
||||
{
|
||||
//reroute each stacked Expression.Call into our own methods that know how to deal
|
||||
//with DynamicNode
|
||||
queryExpr = Expression.Call(
|
||||
typeof(DynamicNodeListOrdering),
|
||||
o.Ascending ? methodAsc : methodDesc,
|
||||
null,
|
||||
queryExpr,
|
||||
Expression.Quote(Expression.Lambda(o.Selector, parameters))
|
||||
);
|
||||
}
|
||||
methodAsc = "ThenBy";
|
||||
methodDesc = "ThenByDescending";
|
||||
}
|
||||
if (isDynamicNodeList)
|
||||
{
|
||||
return typedSource.Provider.CreateQuery(queryExpr);
|
||||
}
|
||||
return source.Provider.CreateQuery(queryExpr);
|
||||
|
||||
}
|
||||
private static object GetObjectAsTypeOrDefault(object value, Type type)
|
||||
{
|
||||
if (type.IsAssignableFrom(value.GetType()))
|
||||
{
|
||||
return (object)Convert.ChangeType(value, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type.IsValueType)
|
||||
{
|
||||
return Activator.CreateInstance(type);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
private static object EvaluateDynamicNodeFunc(DynamicNode node, Func<DynamicNode, object> func)
|
||||
{
|
||||
object value = -1;
|
||||
var firstFuncResult = func(node);
|
||||
if (firstFuncResult is Func<DynamicNode, object>)
|
||||
{
|
||||
value = (firstFuncResult as Func<DynamicNode, object>)(node);
|
||||
}
|
||||
if (firstFuncResult.GetType().IsValueType || firstFuncResult is string)
|
||||
{
|
||||
value = firstFuncResult;
|
||||
}
|
||||
return value;
|
||||
return (IQueryable)Umbraco.Web.Dynamics.DynamicQueryable.OrderBy<DynamicNode>(source, ordering, () => typeof(DynamicNodeListOrdering), values);
|
||||
}
|
||||
|
||||
public static IQueryable Take(this IQueryable source, int count)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
return source.Provider.CreateQuery(
|
||||
Expression.Call(
|
||||
typeof(Queryable), "Take",
|
||||
new Type[] { source.ElementType },
|
||||
source.Expression, Expression.Constant(count)));
|
||||
return (IQueryable)Umbraco.Web.Dynamics.DynamicQueryable.Take(source, count);
|
||||
}
|
||||
|
||||
public static IQueryable Skip(this IQueryable source, int count)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
return source.Provider.CreateQuery(
|
||||
Expression.Call(
|
||||
typeof(Queryable), "Skip",
|
||||
new Type[] { source.ElementType },
|
||||
source.Expression, Expression.Constant(count)));
|
||||
return (IQueryable)Umbraco.Web.Dynamics.DynamicQueryable.Skip(source, count);
|
||||
}
|
||||
|
||||
public static IQueryable GroupBy(this IQueryable source, string keySelector, string elementSelector, params object[] values)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
if (keySelector == null) throw new ArgumentNullException("keySelector");
|
||||
if (elementSelector == null) throw new ArgumentNullException("elementSelector");
|
||||
LambdaExpression keyLambda = Umbraco.Web.Dynamics.DynamicExpression.ParseLambda(source.ElementType, null, keySelector, true, values);
|
||||
LambdaExpression elementLambda = Umbraco.Web.Dynamics.DynamicExpression.ParseLambda(source.ElementType, null, elementSelector, true, values);
|
||||
return source.Provider.CreateQuery(
|
||||
Expression.Call(
|
||||
typeof(Queryable), "GroupBy",
|
||||
new Type[] { source.ElementType, keyLambda.Body.Type, elementLambda.Body.Type },
|
||||
source.Expression, Expression.Quote(keyLambda), Expression.Quote(elementLambda)));
|
||||
return (IQueryable)Umbraco.Web.Dynamics.DynamicQueryable.GroupBy<DynamicNode>(source, keySelector, elementSelector, values);
|
||||
}
|
||||
|
||||
public static bool Any(this IQueryable source)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
return (bool)source.Provider.Execute(
|
||||
Expression.Call(
|
||||
typeof(Queryable), "Any",
|
||||
new Type[] { source.ElementType }, source.Expression));
|
||||
return Umbraco.Web.Dynamics.DynamicQueryable.Any(source);
|
||||
}
|
||||
|
||||
public static int Count(this IQueryable source)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
return (int)source.Provider.Execute(
|
||||
Expression.Call(
|
||||
typeof(Queryable), "Count",
|
||||
new Type[] { source.ElementType }, source.Expression));
|
||||
return Umbraco.Web.Dynamics.DynamicQueryable.Count(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,11 @@ using umbraco.MacroEngines;
|
||||
|
||||
namespace System.Linq.Dynamic
|
||||
{
|
||||
internal class ExpressionParser : Umbraco.Web.Dynamics.ExpressionParser
|
||||
[Obsolete("This class is no longer used, use Umbraco.Web.Dynamics.ExpressionParser<T> instead")]
|
||||
internal class ExpressionParser : Umbraco.Web.Dynamics.ExpressionParser<DynamicNode>
|
||||
{
|
||||
public ExpressionParser(ParameterExpression[] parameters, string expression, object[] values)
|
||||
: base(parameters, expression, values)
|
||||
public ExpressionParser(ParameterExpression[] parameters, string expression, object[] values, bool flagConvertDynamicNullToBooleanFalse)
|
||||
: base(parameters, expression, values, flagConvertDynamicNullToBooleanFalse)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ namespace umbraco.cms.businesslogic.macro
|
||||
///
|
||||
/// If not, the field can be manipulated by a default value given by the MacroPropertyType, this is s
|
||||
/// </summary>
|
||||
[Obsolete]
|
||||
public bool Public
|
||||
{
|
||||
get { return _public; }
|
||||
|
||||
@@ -185,7 +185,7 @@ namespace umbraco.cms.businesslogic.web
|
||||
select count(children.id) as children, umbracoNode.id, umbracoNode.uniqueId, umbracoNode.level, umbracoNode.parentId,
|
||||
cmsDocument.documentUser, coalesce(cmsDocument.templateId, cmsDocumentType.templateNodeId) as templateId,
|
||||
umbracoNode.path, umbracoNode.sortOrder, coalesce(publishCheck.published,0) as isPublished, umbracoNode.createDate,
|
||||
cmsDocument.text, cmsDocument.updateDate, cmsContentVersion.versionDate, cmsContentType.icon, cmsContentType.alias,
|
||||
cmsDocument.text, cmsDocument.updateDate, cmsContentVersion.versionDate, cmsDocument.releaseDate, cmsDocument.expireDate, cmsContentType.icon, cmsContentType.alias,
|
||||
cmsContentType.thumbnail, cmsContentType.description, cmsContentType.masterContentType, cmsContentType.nodeId as contentTypeId,
|
||||
umbracoNode.nodeUser
|
||||
from umbracoNode
|
||||
@@ -202,7 +202,7 @@ namespace umbraco.cms.businesslogic.web
|
||||
cmsDocument.templateId, cmsDocumentType.templateNodeId, umbracoNode.path, umbracoNode.sortOrder,
|
||||
coalesce(publishCheck.published,0), umbracoNode.createDate, cmsDocument.text,
|
||||
cmsContentType.icon, cmsContentType.alias, cmsContentType.thumbnail, cmsContentType.description,
|
||||
cmsContentType.masterContentType, cmsContentType.nodeId, cmsDocument.updateDate, cmsContentVersion.versionDate, umbracoNode.nodeUser
|
||||
cmsContentType.masterContentType, cmsContentType.nodeId, cmsDocument.updateDate, cmsContentVersion.versionDate, cmsDocument.releaseDate, cmsDocument.expireDate, umbracoNode.nodeUser
|
||||
order by {1}
|
||||
";
|
||||
|
||||
@@ -1697,6 +1697,11 @@ namespace umbraco.cms.businesslogic.web
|
||||
, masterContentType
|
||||
, dr.GetInt("contentTypeId")
|
||||
, dr.GetInt("templateId"));
|
||||
|
||||
if (!dr.IsNull("releaseDate"))
|
||||
_release = dr.GetDateTime("releaseDate");
|
||||
if (!dr.IsNull("expireDate"))
|
||||
_expire = dr.GetDateTime("expireDate");
|
||||
}
|
||||
|
||||
protected void SaveXmlPreview(XmlDocument xd)
|
||||
|
||||
@@ -65,9 +65,8 @@ namespace umbraco.uicontrols.TreePicker
|
||||
public abstract string ModalWindowTitle { get; }
|
||||
|
||||
/// <summary>
|
||||
/// If item has been selected or stored, this will query the db for it's title
|
||||
/// If item has been selected or stored, this will query the db for its title
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected virtual string GetItemTitle()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ItemIdValue.Value))
|
||||
@@ -81,6 +80,31 @@ namespace umbraco.uicontrols.TreePicker
|
||||
return "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Just like GetItemTitle, except returns the full path (breadcrumbs) of the node
|
||||
/// </summary>
|
||||
protected virtual string GetItemBreadcrumbs()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ItemIdValue.Value))
|
||||
{
|
||||
try
|
||||
{
|
||||
int nodeId = int.Parse(ItemIdValue.Value);
|
||||
CMSNode node = new CMSNode(nodeId);
|
||||
string title = node.Text;
|
||||
string separator = " > ";
|
||||
while (node != null && node.Level > 1)
|
||||
{
|
||||
node = node.Parent;
|
||||
title = node.Text + separator + title;
|
||||
}
|
||||
return title;
|
||||
}
|
||||
catch (ArgumentException) { /*the node does not exist! we will ignore*/ }
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Outputs the JavaScript instances used to make this control work
|
||||
/// </summary>
|
||||
@@ -156,6 +180,7 @@ namespace umbraco.uicontrols.TreePicker
|
||||
ItemTitle = new HtmlGenericControl("span");
|
||||
ItemTitle.ID = "title";
|
||||
ItemTitle.Style.Add(HtmlTextWriterStyle.FontWeight, "bold");
|
||||
ItemTitle.Attributes.Add("class", "treePickerTitle"); // solely for styling, e.g. with an underline or dotted border, etc.
|
||||
ButtonContainer.Controls.Add(ItemTitle);
|
||||
ButtonContainer.Controls.Add(new LiteralControl(" "));
|
||||
ButtonContainer.Controls.Add(new LiteralControl(" "));
|
||||
@@ -200,6 +225,7 @@ namespace umbraco.uicontrols.TreePicker
|
||||
else
|
||||
{
|
||||
ItemTitle.InnerText = GetItemTitle();
|
||||
ItemTitle.Attributes.Add("title", GetItemBreadcrumbs()); // Adding full path/meta info (Issue U4-192)
|
||||
}
|
||||
|
||||
ChooseLink.HRef = string.Format("javascript:mc_{0}.LaunchPicker();", this.ClientID);
|
||||
|
||||
@@ -6,7 +6,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
Umbraco.Controls.TreePicker = function(clientId, label, itemIdValueClientID, itemTitleClientID, itemPickerUrl, width, height, showHeader, umbracoPath) {
|
||||
var obj = {
|
||||
_itemPickerUrl: itemPickerUrl,
|
||||
_webServiceUrl: umbracoPath + "/webservices/legacyAjaxCalls.asmx/GetNodeName",
|
||||
_webServiceUrl: umbracoPath + "/webservices/legacyAjaxCalls.asmx/GetNodeBreadcrumbs",
|
||||
_label: label,
|
||||
_width: width,
|
||||
_height: height,
|
||||
@@ -37,14 +37,23 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
contentType: "application/json; charset=utf-8",
|
||||
dataType: "json",
|
||||
success: function(msg) {
|
||||
$("#" + _this._itemTitleClientID).html(msg.d);
|
||||
$("#" + _this._itemTitleClientID).parent().show();
|
||||
var a = msg.d;
|
||||
var name = a[a.length - 1];
|
||||
var breadcrumbs = a.join(" > ");
|
||||
$("#" + _this._itemTitleClientID)
|
||||
.html(name)
|
||||
.attr('title', breadcrumbs)
|
||||
.parent()
|
||||
.show();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
ClearSelection: function() {
|
||||
$("#" + this._itemTitleClientID).parent().hide();
|
||||
$("#" + this._itemTitleClientID)
|
||||
.attr('title', '')
|
||||
.parent()
|
||||
.hide();
|
||||
$("#" + this._itemIdValueClientID).val('');
|
||||
}
|
||||
};
|
||||
@@ -54,17 +63,35 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
Umbraco.Controls.TreePicker.inst[clientId] = obj;
|
||||
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ready(function () {
|
||||
// Tooltip only Text
|
||||
$('.treePickerTitle').hover(function () {
|
||||
// Hover over code
|
||||
var title = $(this).attr('title');
|
||||
$(this).data('tipText', title).removeAttr('title');
|
||||
$('<p class="treePickerTooltip"></p>').text(title).appendTo('body').fadeIn('fast');;
|
||||
}, function () {
|
||||
// Hover out code
|
||||
$(this).attr('title', $(this).data('tipText'));
|
||||
$('.treePickerTooltip').remove();
|
||||
}).mousemove(function (e) {
|
||||
var mousex = e.pageX + 10; //Get X coordinates
|
||||
var mousey = e.pageY + 5; //Get Y coordinates
|
||||
$('.treePickerTooltip').css({ top: mousey, left: mousex });
|
||||
});
|
||||
});
|
||||
|
||||
// Static methods
|
||||
|
||||
//return the existing picker object based on client id of the control
|
||||
Umbraco.Controls.TreePicker.GetPickerById = function(id) {
|
||||
return Umbraco.Controls.TreePicker.inst[id] || null;
|
||||
};
|
||||
|
||||
|
||||
// instance manager
|
||||
Umbraco.Controls.TreePicker.cntr = 0;
|
||||
Umbraco.Controls.TreePicker.inst = {};
|
||||
|
||||
|
||||
})(jQuery);
|
||||
|
||||
Reference in New Issue
Block a user