Merge with 4.10.0

This commit is contained in:
Morten@Thinkpad-X220
2012-10-08 08:50:01 -02:00
62 changed files with 1130 additions and 626 deletions

View File

@@ -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");
}

View File

@@ -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);
}
}
}

View File

@@ -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());
}
}
}

View File

@@ -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)

View File

@@ -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()
{

View File

@@ -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" />

View File

@@ -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" />

View File

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

View File

@@ -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" />

View File

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

View File

@@ -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">&nbsp;</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>

View File

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

View File

@@ -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"

View File

@@ -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">&nbsp;</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">&nbsp;</span></span></span></a>
</div>
<div id="macroMenu" style="width: 285px">
<asp:Repeater ID="rpt_macros" runat="server">

View File

@@ -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;

View File

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

View File

@@ -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)

View File

@@ -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;

View File

@@ -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",

View File

@@ -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
{

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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);

View File

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

View File

@@ -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
{

View File

@@ -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)

View File

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

View File

@@ -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);

View File

@@ -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">&nbsp;</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>

View File

@@ -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;

View File

@@ -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";
}

View File

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

View File

@@ -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;

View File

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

View File

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

View File

@@ -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;

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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();
}

View File

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

View File

@@ -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);

View File

@@ -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);
}
}
}

View File

@@ -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)
{
}
}

View File

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

View File

@@ -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)

View File

@@ -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("&nbsp;"));
ButtonContainer.Controls.Add(new LiteralControl("&nbsp;"));
@@ -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);

View File

@@ -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);