diff --git a/src/Umbraco.Core/DataTableExtensions.cs b/src/Umbraco.Core/DataTableExtensions.cs index 38b49cae12..8c29d948ac 100644 --- a/src/Umbraco.Core/DataTableExtensions.cs +++ b/src/Umbraco.Core/DataTableExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Data; using System.Linq; @@ -16,14 +17,12 @@ namespace Umbraco.Core /// internal static class DataTableExtensions { - - private static readonly Hashtable AliasToNames = new Hashtable(); - private static readonly ReaderWriterLockSlim Lock = new ReaderWriterLockSlim(); + /// /// Creates a DataTable with the specified alias and columns and uses a callback to populate the headers. /// - /// + /// /// /// /// @@ -32,36 +31,27 @@ namespace Umbraco.Core /// DynamicDocument extensions for legacy reasons. /// public static DataTable GenerateDataTable( - string alias, + string tableAlias, Func>> getHeaders, Func>, IEnumerable>>>> rowData) { - var dt = new DataTable(alias); + var dt = new DataTable(tableAlias); - //get the standard column headers from the standard data (not user data) - var tableData = rowData(); - var standardColHeaders = tableData.SelectMany(x => x.Item1).Select(x => x.Key).Distinct(); - - var userPropColHeaders = new List(); - // get user property column headers - var propertyHeaders = GetPropertyHeaders(alias, getHeaders); - var ide = propertyHeaders.GetEnumerator(); - while (ide.MoveNext()) - { - userPropColHeaders.Add(ide.Value.ToString()); - } + //get all row data + var tableData = rowData().ToArray(); - //now add all the columns, standard val headers first, then user val headers - foreach (var dc in standardColHeaders.Union(userPropColHeaders).Select(c => new DataColumn(c))) + //get all headers + var propertyHeaders = GetPropertyHeaders(tableAlias, getHeaders); + foreach(var h in propertyHeaders) { - dt.Columns.Add(dc); + dt.Columns.Add(new DataColumn(h.Value)); } - + //add row data - foreach(var r in rowData()) + foreach(var r in tableData) { dt.PopulateRow( - (Hashtable)AliasToNames[alias], + propertyHeaders, r.Item1, r.Item2); } @@ -101,29 +91,16 @@ namespace Umbraco.Core )); } - private static Hashtable GetPropertyHeaders(string alias, Func>> getHeaders) - { - using (var l = new UpgradeableReadLock(Lock)) - { - if (AliasToNames.ContainsKey(alias)) - return (Hashtable)AliasToNames[alias]; - - l.UpgradeToWriteLock(); - - var headers = getHeaders(alias); - var def = new Hashtable(); - foreach (var pt in headers) - def.Add(pt.Key, pt.Value); - AliasToNames.Add(alias, def); - - return def; - } - + private static IDictionary GetPropertyHeaders(string alias, Func>> getHeaders) + { + var headers = getHeaders(alias); + var def = headers.ToDictionary(pt => pt.Key, pt => pt.Value); + return def; } private static void PopulateRow( this DataTable dt, - IDictionary aliasesToNames, + IDictionary aliasesToNames, IEnumerable> standardVals, IEnumerable> userPropertyVals) { @@ -134,7 +111,7 @@ namespace Umbraco.Core } foreach (var p in userPropertyVals.Where(p => p.Value != null)) { - dr[aliasesToNames[p.Key].ToString()] = p.Value; + dr[aliasesToNames[p.Key]] = p.Value; } dt.Rows.Add(dr); } diff --git a/src/Umbraco.Core/DocumentExtensions.cs b/src/Umbraco.Core/DocumentExtensions.cs index 70ee818524..af670fe03e 100644 --- a/src/Umbraco.Core/DocumentExtensions.cs +++ b/src/Umbraco.Core/DocumentExtensions.cs @@ -1,9 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Data; using System.Linq; using Umbraco.Core.Models; +using umbraco.interfaces; namespace Umbraco.Core { - internal static class DocumentExtensions + public static class DocumentExtensions { /// /// Returns the property as the specified type, if the property is not found or does not convert @@ -39,5 +43,6 @@ namespace Umbraco.Core { return d.Properties.FirstOrDefault(p => p.Alias.InvariantEquals(alias)); } + } } \ No newline at end of file diff --git a/src/Umbraco.Core/Dynamics/DynamicDocument.cs b/src/Umbraco.Core/Dynamics/DynamicDocument.cs index abe26aa058..88a65dec8b 100644 --- a/src/Umbraco.Core/Dynamics/DynamicDocument.cs +++ b/src/Umbraco.Core/Dynamics/DynamicDocument.cs @@ -180,57 +180,6 @@ namespace Umbraco.Core.Dynamics //} - //public DynamicDocumentList Search(string term, bool useWildCards = true, string searchProvider = null) - //{ - // var searcher = Examine.ExamineManager.Instance.DefaultSearchProvider; - // if(!string.IsNullOrEmpty(searchProvider)) - // searcher = Examine.ExamineManager.Instance.SearchProviderCollection[searchProvider]; - - // var t = term.Escape().Value; - // if (useWildCards) - // t = term.MultipleCharacterWildcard().Value; - - // string luceneQuery = "+__Path:(" + this.Path.Replace("-", "\\-") + "*) +" + t; - // var crit = searcher.CreateSearchCriteria().RawQuery(luceneQuery); - - // return Search(crit, searcher); - //} - - //public DynamicDocumentList SearchDescendants(string term, bool useWildCards = true, string searchProvider = null) - //{ - // return Search(term, useWildCards, searchProvider); - //} - - //public DynamicDocumentList SearchChildren(string term, bool useWildCards = true, string searchProvider = null) - //{ - // var searcher = Examine.ExamineManager.Instance.DefaultSearchProvider; - // if (!string.IsNullOrEmpty(searchProvider)) - // searcher = Examine.ExamineManager.Instance.SearchProviderCollection[searchProvider]; - - // var t = term.Escape().Value; - // if (useWildCards) - // t = term.MultipleCharacterWildcard().Value; - - // string luceneQuery = "+parentID:" + this.Id.ToString() + " +" + t; - // var crit = searcher.CreateSearchCriteria().RawQuery(luceneQuery); - - // return Search(crit, searcher); - //} - - - //public DynamicDocumentList Search(Examine.SearchCriteria.ISearchCriteria criteria, Examine.Providers.BaseSearchProvider searchProvider = null) - //{ - // var s = Examine.ExamineManager.Instance.DefaultSearchProvider; - // if (searchProvider != null) - // s = searchProvider; - - // var results = s.Search(criteria); - // return ExamineSearchUtill.convertSearchResultToDynamicNode(results); - //} - - - - public bool HasProperty(string name) { if (_backingItem != null) @@ -505,9 +454,6 @@ namespace Umbraco.Core.Dynamics var name = binder.Name; - //TODO: Refactor the below into multiple methods that return Attempt as this - // will be much easier to read - //check the cache first! if (_cachedMemberOutput.TryGetValue(name, out result)) { @@ -541,51 +487,7 @@ namespace Umbraco.Core.Dynamics //alwasy return true if we haven't thrown an exception though I'm wondering if we return 'false' if .Net throws an exception for us?? return true; - } - - //private bool TryCreateInstanceRazorDataTypeModel(Guid dataType, Type dataTypeType, string value, out object result) - //{ - // //HttpContext.Current.Trace.Write(string.Format("Found dataType {0} for GUID {1}", dataTypeType.FullName, dataType)); - // IRazorDataTypeModel razorDataTypeModel = Activator.CreateInstance(dataTypeType, false) as IRazorDataTypeModel; - // //HttpContext.Current.Trace.Write(string.Format("Instantiating {0}...", dataTypeType.FullName)); - // if (razorDataTypeModel != null) - // { - // //HttpContext.Current.Trace.Write("Success"); - // object instance = null; - // //HttpContext.Current.Trace.Write("Calling Init on razorDataTypeModel"); - // if (razorDataTypeModel.Init(_n.Id, value, out instance)) - // { - // if (instance != null) - // { - // //HttpContext.Current.Trace.Write(string.Format("razorDataTypeModel successfully instantiated and returned a valid instance of type {0}", instance.GetType().FullName)); - // } - // else - // { - // //HttpContext.Current.Trace.Warn("razorDataTypeModel successfully instantiated but returned null for instance"); - // } - // result = instance; - // return true; - // } - // else - // { - // if (instance != null) - // { - // //HttpContext.Current.Trace.Write(string.Format("razorDataTypeModel returned false but returned a valid instance of type {0}", instance.GetType().FullName)); - // } - // else - // { - // //HttpContext.Current.Trace.Warn("razorDataTypeModel successfully instantiated but returned null for instance"); - // } - // } - // } - // else - // { - // //HttpContext.Current.Trace.Write("Failed"); - // //HttpContext.Current.Trace.Warn(string.Format("DataTypeModel {0} failed to instantiate, perhaps it is lacking a parameterless constructor or doesn't implement IRazorDataTypeModel?", dataTypeType.FullName)); - // } - // result = null; - // return false; - //} + } /// /// Returns a property defined on the document object as a member property using reflection diff --git a/src/Umbraco.Core/Dynamics/IDynamicDocumentDataSource.cs b/src/Umbraco.Core/Dynamics/IDynamicDocumentDataSource.cs index 014563cc61..c84e1565ac 100644 --- a/src/Umbraco.Core/Dynamics/IDynamicDocumentDataSource.cs +++ b/src/Umbraco.Core/Dynamics/IDynamicDocumentDataSource.cs @@ -11,5 +11,6 @@ namespace Umbraco.Core.Dynamics internal interface IDynamicDocumentDataSource { Guid GetDataType(string docTypeAlias, string propertyAlias); + } } \ No newline at end of file diff --git a/src/Umbraco.Tests/DynamicDocument/DynamicDocumentTests.cs b/src/Umbraco.Tests/DynamicDocument/DynamicDocumentTests.cs index 84924ae3ab..98c59dc1d3 100644 --- a/src/Umbraco.Tests/DynamicDocument/DynamicDocumentTests.cs +++ b/src/Umbraco.Tests/DynamicDocument/DynamicDocumentTests.cs @@ -1,13 +1,204 @@ using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; using NUnit.Framework; using Umbraco.Core.Dynamics; +using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +using Umbraco.Tests.Routing; +using Umbraco.Tests.TestHelpers; using Umbraco.Web; +using Umbraco.Web.Routing; using umbraco.BusinessLogic; +using umbraco.cms.businesslogic; using umbraco.cms.businesslogic.template; +using umbraco.cms.businesslogic.web; namespace Umbraco.Tests.DynamicDocument { + + /// + /// Unit tests for IDocument and extensions + /// + [TestFixture] + public class DocumentTests : BaseRoutingTest + { + public override void Initialize() + { + base.Initialize(); + //need to specify a different callback for testing + DocumentExtensions.GetPropertyAliasesAndNames = s => + { + var userFields = new Dictionary() + { + {"property1", "Property 1"}, + {"property2", "Property 2"} + }; + if (s == "Child") + { + userFields.Add("property4", "Property 4"); + } + else + { + userFields.Add("property3", "Property 3"); + } + + //ensure the standard fields are there + var allFields = new Dictionary() + { + {"Id", "Id"}, + {"NodeName", "NodeName"}, + {"NodeTypeAlias", "NodeTypeAlias"}, + {"CreateDate", "CreateDate"}, + {"UpdateDate", "UpdateDate"}, + {"CreatorName", "CreatorName"}, + {"WriterName", "WriterName"}, + {"Url", "Url"} + }; + foreach (var f in userFields.Where(f => !allFields.ContainsKey(f.Key))) + { + allFields.Add(f.Key, f.Value); + } + return allFields; + }; + var routingContext = GetRoutingContext("/test"); + + //set the UmbracoContext.Current since the extension methods rely on it + UmbracoContext.Current = routingContext.UmbracoContext; + } + + public override void TearDown() + { + base.TearDown(); + DocumentExtensions.GetPropertyAliasesAndNames = null; + UmbracoContext.Current = null; + } + + [Test] + public void To_DataTable() + { + var doc = GetDocument(true, 1); + var dt = doc.ChildrenAsTable(); + + Assert.AreEqual(11, dt.Columns.Count); + Assert.AreEqual(3, dt.Rows.Count); + Assert.AreEqual("value4", dt.Rows[0]["Property 1"]); + Assert.AreEqual("value5", dt.Rows[0]["Property 2"]); + Assert.AreEqual("value6", dt.Rows[0]["Property 4"]); + Assert.AreEqual("value7", dt.Rows[1]["Property 1"]); + Assert.AreEqual("value8", dt.Rows[1]["Property 2"]); + Assert.AreEqual("value9", dt.Rows[1]["Property 4"]); + Assert.AreEqual("value10", dt.Rows[2]["Property 1"]); + Assert.AreEqual("value11", dt.Rows[2]["Property 2"]); + Assert.AreEqual("value12", dt.Rows[2]["Property 4"]); + } + + [Test] + public void To_DataTable_With_Filter() + { + var doc = GetDocument(true, 1); + //change a doc type alias + ((TestDocument) doc.Children.ElementAt(0)).DocumentTypeAlias = "DontMatch"; + + var dt = doc.ChildrenAsTable("Child"); + + Assert.AreEqual(11, dt.Columns.Count); + Assert.AreEqual(2, dt.Rows.Count); + Assert.AreEqual("value7", dt.Rows[0]["Property 1"]); + Assert.AreEqual("value8", dt.Rows[0]["Property 2"]); + Assert.AreEqual("value9", dt.Rows[0]["Property 4"]); + Assert.AreEqual("value10", dt.Rows[1]["Property 1"]); + Assert.AreEqual("value11", dt.Rows[1]["Property 2"]); + Assert.AreEqual("value12", dt.Rows[1]["Property 4"]); + } + + [Test] + public void To_DataTable_No_Rows() + { + var doc = GetDocument(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 IDocument GetDocument(bool createChildren, int indexVals) + { + var d = new TestDocument + { + CreateDate = DateTime.Now, + CreatorId = 1, + CreatorName = "Shannon", + DocumentTypeAlias = createChildren? "Parent" : "Child", + DocumentTypeId = 2, + Id = 3, + SortOrder = 4, + TemplateId = 5, + UpdateDate = DateTime.Now, + Path = "-1,3", + UrlName = "home-page", + Name = "Page" + Guid.NewGuid().ToString(), + Version = Guid.NewGuid(), + WriterId = 1, + WriterName = "Shannon", + Parent = null, + Level = 1, + Properties = new Collection( + new List() + { + new PropertyResult("property1", "value" + indexVals, Guid.NewGuid(), PropertyResultType.UserProperty), + new PropertyResult("property2", "value" + (indexVals + 1), Guid.NewGuid(), PropertyResultType.UserProperty) + }), + Children = new List() + }; + if (createChildren) + { + d.Children = new List() + { + GetDocument(false, indexVals + 3), + GetDocument(false, indexVals + 6), + GetDocument(false, indexVals + 9) + }; + } + if (!createChildren) + { + //create additional columns, used to test the different columns for child nodes + d.Properties.Add(new PropertyResult("property4", "value" + (indexVals + 2), Guid.NewGuid(), PropertyResultType.UserProperty)); + } + else + { + d.Properties.Add(new PropertyResult("property3", "value" + (indexVals + 2), Guid.NewGuid(), PropertyResultType.UserProperty)); + } + return d; + } + + + private class TestDocument : IDocument + { + public IDocument Parent { get; set; } + public int Id { get; set; } + public int TemplateId { get; set; } + public int SortOrder { get; set; } + public string Name { get; set; } + public string UrlName { get; set; } + public string DocumentTypeAlias { get; set; } + public int DocumentTypeId { get; set; } + public string WriterName { get; set; } + public string CreatorName { get; set; } + public int WriterId { get; set; } + public int CreatorId { get; set; } + public string Path { get; set; } + public DateTime CreateDate { get; set; } + public DateTime UpdateDate { get; set; } + public Guid Version { get; set; } + public int Level { get; set; } + public Collection Properties { get; set; } + public IEnumerable Children { get; set; } + } + + } + [TestFixture] public class DynamicDocumentTests : DynamicDocumentTestsBase { @@ -27,11 +218,11 @@ namespace Umbraco.Tests.DynamicDocument public override void TearDown() { base.TearDown(); - + PropertyEditorValueConvertersResolver.Reset(); } - + protected override dynamic GetDynamicNode(int id) { diff --git a/src/Umbraco.Tests/Routing/LookupByAliasTests.cs b/src/Umbraco.Tests/Routing/LookupByAliasTests.cs index 800a436dc1..59dad90a68 100644 --- a/src/Umbraco.Tests/Routing/LookupByAliasTests.cs +++ b/src/Umbraco.Tests/Routing/LookupByAliasTests.cs @@ -1,4 +1,5 @@ using NUnit.Framework; +using Umbraco.Tests.TestHelpers; using Umbraco.Web.Routing; using umbraco.BusinessLogic; using umbraco.cms.businesslogic.template; diff --git a/src/Umbraco.Tests/Routing/LookupByIdTests.cs b/src/Umbraco.Tests/Routing/LookupByIdTests.cs index 035fafc249..c70088f577 100644 --- a/src/Umbraco.Tests/Routing/LookupByIdTests.cs +++ b/src/Umbraco.Tests/Routing/LookupByIdTests.cs @@ -1,4 +1,5 @@ using NUnit.Framework; +using Umbraco.Tests.TestHelpers; using Umbraco.Web.Routing; using umbraco.BusinessLogic; using umbraco.cms.businesslogic.template; diff --git a/src/Umbraco.Tests/Routing/LookupByNiceUrlAndTemplateTests.cs b/src/Umbraco.Tests/Routing/LookupByNiceUrlAndTemplateTests.cs index 562dc31999..412fb03c0b 100644 --- a/src/Umbraco.Tests/Routing/LookupByNiceUrlAndTemplateTests.cs +++ b/src/Umbraco.Tests/Routing/LookupByNiceUrlAndTemplateTests.cs @@ -1,4 +1,5 @@ using NUnit.Framework; +using Umbraco.Tests.TestHelpers; using Umbraco.Web.Routing; using umbraco.BusinessLogic; using umbraco.cms.businesslogic.template; diff --git a/src/Umbraco.Tests/Routing/LookupByNiceUrlTests.cs b/src/Umbraco.Tests/Routing/LookupByNiceUrlTests.cs index 6adca048b4..de76880efc 100644 --- a/src/Umbraco.Tests/Routing/LookupByNiceUrlTests.cs +++ b/src/Umbraco.Tests/Routing/LookupByNiceUrlTests.cs @@ -1,5 +1,6 @@ using System.Configuration; using NUnit.Framework; +using Umbraco.Tests.TestHelpers; using Umbraco.Web.Routing; using umbraco.BusinessLogic; using umbraco.cms.businesslogic.template; diff --git a/src/Umbraco.Tests/Routing/LookupByPageIdQueryTests.cs b/src/Umbraco.Tests/Routing/LookupByPageIdQueryTests.cs index 875509d606..0d3939316a 100644 --- a/src/Umbraco.Tests/Routing/LookupByPageIdQueryTests.cs +++ b/src/Umbraco.Tests/Routing/LookupByPageIdQueryTests.cs @@ -1,5 +1,6 @@ using NUnit.Framework; using Rhino.Mocks; +using Umbraco.Tests.TestHelpers; using Umbraco.Web.Routing; using umbraco.BusinessLogic; using umbraco.cms.businesslogic.template; diff --git a/src/Umbraco.Tests/Routing/NiceUrlProviderTests.cs b/src/Umbraco.Tests/Routing/NiceUrlProviderTests.cs index 102bf8d744..fd3c20471e 100644 --- a/src/Umbraco.Tests/Routing/NiceUrlProviderTests.cs +++ b/src/Umbraco.Tests/Routing/NiceUrlProviderTests.cs @@ -1,6 +1,7 @@ using System; using System.Configuration; using NUnit.Framework; +using Umbraco.Tests.TestHelpers; using Umbraco.Web.Routing; namespace Umbraco.Tests.Routing diff --git a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs index 05d4965bdf..843ab53c74 100644 --- a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs +++ b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs @@ -2,6 +2,7 @@ using System.Web.Routing; using NUnit.Framework; using Umbraco.Tests.Stubs; +using Umbraco.Tests.TestHelpers; using Umbraco.Web; using Umbraco.Web.Mvc; using Umbraco.Web.Routing; diff --git a/src/Umbraco.Tests/Routing/BaseRoutingTest.cs b/src/Umbraco.Tests/TestHelpers/BaseRoutingTest.cs similarity index 87% rename from src/Umbraco.Tests/Routing/BaseRoutingTest.cs rename to src/Umbraco.Tests/TestHelpers/BaseRoutingTest.cs index 2dc58d9937..3da022c4ed 100644 --- a/src/Umbraco.Tests/Routing/BaseRoutingTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseRoutingTest.cs @@ -3,12 +3,11 @@ using System.Linq; using System.Web.Routing; using NUnit.Framework; using Umbraco.Tests.Stubs; -using Umbraco.Tests.TestHelpers; using Umbraco.Web; using Umbraco.Web.Routing; using umbraco.cms.businesslogic.template; -namespace Umbraco.Tests.Routing +namespace Umbraco.Tests.TestHelpers { [TestFixture, RequiresSTA] public abstract class BaseRoutingTest : BaseWebTest @@ -40,13 +39,17 @@ namespace Umbraco.Tests.Routing var umbracoContext = GetUmbracoContext(url, templateId, routeData); var contentStore = new DefaultPublishedContentStore(); var niceUrls = new NiceUrlProvider(contentStore, umbracoContext); - var routingRequest = new RoutingContext( + var routingContext = new RoutingContext( umbracoContext, Enumerable.Empty(), new FakeLastChanceLookup(), contentStore, niceUrls); - return routingRequest; + + //assign the routing context back to the umbraco context + umbracoContext.RoutingContext = routingContext; + + return routingContext; } /// diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 2dcbc0d25f..eda0dcba03 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -67,7 +67,7 @@ - + diff --git a/src/Umbraco.Web.UI/umbraco/dashboard/ChangePassword.ascx b/src/Umbraco.Web.UI/umbraco/dashboard/ChangePassword.ascx new file mode 100644 index 0000000000..7c28c9ff46 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/dashboard/ChangePassword.ascx @@ -0,0 +1,61 @@ +<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="ChangePassword.ascx.cs" Inherits="umbraco.presentation.umbraco.dashboard.ChangePassword" %> +<%@ Register TagPrefix="umb" Namespace="ClientDependency.Core.Controls" Assembly="ClientDependency.Core" %> + + + + + + +
+

<%=umbraco.ui.Text("changePassword") %>

+ Users + +

<%=umbraco.ui.Text("changePasswordDescription") %>

+ +
+

+
+
+
    +
  1. + + <%=umbraco.ui.Text("username") %>: + <%=umbraco.BusinessLogic.User.GetCurrent().Name%> + +
  2. +
  3. + + <%=umbraco.ui.Text("passwordEnterNew") %>: + + * + +
  4. +
  5. + + <%=umbraco.ui.Text("passwordConfirm") %>: + + * + <%=umbraco.ui.Text("passwordMismatch") %> + +
  6. +
+

+ +

+
+ +

<%=umbraco.ui.Text("passwordChanged") %>!

+
+
diff --git a/src/Umbraco.Web.UI/umbraco/dashboard/DesktopMediaUploader.ascx b/src/Umbraco.Web.UI/umbraco/dashboard/DesktopMediaUploader.ascx new file mode 100644 index 0000000000..3869aa8547 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/dashboard/DesktopMediaUploader.ascx @@ -0,0 +1,50 @@ +<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="DesktopMediaUploader.ascx.cs" Inherits="umbraco.presentation.umbraco.dashboard.DesktopMediaUploader" %> +<%@ Register Assembly="controls" Namespace="umbraco.uicontrols" TagPrefix="umb" %> +<%@ Register Assembly="ClientDependency.Core" Namespace="ClientDependency.Core.Controls" TagPrefix="umb" %> + + + + +
+

Desktop Media Uploader

+ Umbraco +

Desktop Media Uploader is a small desktop application that you can install on your computer which allows you to easily upload media items directly to the media section.

+

The badge below will auto configure itself based upon whether you already have Desktop Media Uploader installed or not.

+

Just click the Install Now / Upgrade Now / Launch Now link to perform that action.

+
+
+
+ + +

+

+ Download Desktop Media Uploader now.

This application requires Adobe® AIR™ to be installed for Mac OS or Windows. +
+

+ +
+
+
+
+
\ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco/dashboard/DeveloperDashboardIntro.ascx b/src/Umbraco.Web.UI/umbraco/dashboard/DeveloperDashboardIntro.ascx new file mode 100644 index 0000000000..f8222e3b60 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/dashboard/DeveloperDashboardIntro.ascx @@ -0,0 +1,28 @@ +<%@ Control Language="C#" AutoEventWireup="true" %> + +<%@ Register Assembly="controls" Namespace="umbraco.uicontrols" TagPrefix="umb" %> +<%@ Register Assembly="ClientDependency.Core" Namespace="ClientDependency.Core.Controls" TagPrefix="umb" %> + + + +
+

Start here

+ Umbraco +

This section contains the tools to add advanced features to your Umbraco site

+

From here you can explore and install packages, create macros, add data types, and much more. Start by exploring the below links or videos.

+

Find out more:

+
+
+
+ +
+
+
+
diff --git a/src/Umbraco.Web.UI/umbraco/dashboard/DeveloperDashboardVideos.ascx b/src/Umbraco.Web.UI/umbraco/dashboard/DeveloperDashboardVideos.ascx new file mode 100644 index 0000000000..8e10849640 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/dashboard/DeveloperDashboardVideos.ascx @@ -0,0 +1,107 @@ +<%@ Control Language="C#" AutoEventWireup="true" %> +<%@ Register Assembly="controls" Namespace="umbraco.uicontrols" TagPrefix="umb" %> +<%@ Register Assembly="ClientDependency.Core" Namespace="ClientDependency.Core.Controls" TagPrefix="umb" %> + + + + + + +
+

Watch and learn

+ Videos +

Hours of Umbraco training videos are only a click away

+

Want to master Umbraco Macros and more? Spend a couple of minutes learning some best practices by watching one of these videos about using Umbraco. And visit umbraco.tv for even more Umbraco videos

+

To get you started:

+
Loading...
+
\ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco/dashboard/FeedProxy.aspx b/src/Umbraco.Web.UI/umbraco/dashboard/FeedProxy.aspx new file mode 100644 index 0000000000..78c02767e2 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/dashboard/FeedProxy.aspx @@ -0,0 +1,2 @@ +<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="FeedProxy.aspx.cs" Inherits="dashboardUtilities.FeedProxy" %> +<%@ OutputCache Duration="1800" VaryByParam="url" %> diff --git a/src/Umbraco.Web.UI/umbraco/dashboard/LatestEdits.ascx b/src/Umbraco.Web.UI/umbraco/dashboard/LatestEdits.ascx new file mode 100644 index 0000000000..48ad25fec3 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/dashboard/LatestEdits.ascx @@ -0,0 +1,14 @@ +<%@ Control Language="c#" AutoEventWireup="True" Codebehind="LatestEdits.ascx.cs" Inherits="dashboardUtilities.LatestEdits" %> +<%@ Register TagPrefix="umb" Namespace="ClientDependency.Core.Controls" Assembly="ClientDependency.Core" %> + + + +
+

<%=umbraco.ui.Text("defaultdialogs", "lastEdited")%>

+ Umbraco + + + <%# PrintNodeName(DataBinder.Eval(Container.DataItem, "NodeId"), DataBinder.Eval(Container.DataItem, "datestamp")) %> + + +
diff --git a/src/Umbraco.Web.UI/umbraco/dashboard/MediaDashboardFolderBrowser.ascx b/src/Umbraco.Web.UI/umbraco/dashboard/MediaDashboardFolderBrowser.ascx new file mode 100644 index 0000000000..f4094b4455 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/dashboard/MediaDashboardFolderBrowser.ascx @@ -0,0 +1,4 @@ +<%@ Control Language="C#" AutoEventWireup="true" %> +<%@ Register TagPrefix="umb" Namespace="Umbraco.Web.UI.Controls" Assembly="umbraco" %> + + \ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco/dashboard/MediaDashboardIntro.ascx b/src/Umbraco.Web.UI/umbraco/dashboard/MediaDashboardIntro.ascx new file mode 100644 index 0000000000..f659eadd29 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/dashboard/MediaDashboardIntro.ascx @@ -0,0 +1,27 @@ +<%@ Control Language="C#" AutoEventWireup="true" %> +<%@ Register Namespace="umbraco.uicontrols" Assembly="controls" TagPrefix="umb" %> +<%@ Register TagPrefix="umb" Namespace="ClientDependency.Core.Controls" Assembly="ClientDependency.Core" %> + + + +
+

Start here

+ Umbraco +

Get started with Media right now

+

Use the tool below to upload your images or documents to a media folder.

+

Follow these steps:

+
+
+
+
    +
  • Click Install and follow the on screen instructions to install the Desktop Media Uploader
  • +
  • Enter your login details for the site and click Sign In
  • +
  • Choose a media folder to upload files to from the Upload files to... dropdown list
  • +
  • Drag the files and folders you wish to upload directly into the Desktop Media Uploader application
  • +
  • Click Upload to start uploading
  • +
+

For a more thorough guide on how to use the Desktop Media Uploader, checkout this video.

+
+
+
+
diff --git a/src/Umbraco.Web.UI/umbraco/dashboard/MediaDashboardVideos.ascx b/src/Umbraco.Web.UI/umbraco/dashboard/MediaDashboardVideos.ascx new file mode 100644 index 0000000000..22372642e2 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/dashboard/MediaDashboardVideos.ascx @@ -0,0 +1,107 @@ +<%@ Control Language="C#" AutoEventWireup="true" %> +<%@ Register Assembly="controls" Namespace="umbraco.uicontrols" TagPrefix="umb" %> +<%@ Register Assembly="ClientDependency.Core" Namespace="ClientDependency.Core.Controls" TagPrefix="umb" %> + + + + + + +
+

Watch and learn

+ Videos +

Hours of Umbraco training videos are only a click away

+

Want to master Umbraco? Spend a couple of minutes learning some best practices by watching one of these videos about using Umbraco. And visit umbraco.tv for even more Umbraco videos

+

To get you started:

+
Loading...
+
\ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco/dashboard/MembersDashboardIntro.ascx b/src/Umbraco.Web.UI/umbraco/dashboard/MembersDashboardIntro.ascx new file mode 100644 index 0000000000..4e78fb0540 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/dashboard/MembersDashboardIntro.ascx @@ -0,0 +1,22 @@ +<%@ Control Language="C#" AutoEventWireup="true" %> +<%@ Register Assembly="controls" Namespace="umbraco.uicontrols" TagPrefix="umb" %> +<%@ Register Assembly="ClientDependency.Core" Namespace="ClientDependency.Core.Controls" TagPrefix="umb" %> + + + +
+

Start here

+ Umbraco +

Get started with Members right now

+

Use the tool below to search for an existing member.

+

More about members

+
+
+
+ +
+
+
+
diff --git a/src/Umbraco.Web.UI/umbraco/dashboard/MembersDashboardVideos.ascx b/src/Umbraco.Web.UI/umbraco/dashboard/MembersDashboardVideos.ascx new file mode 100644 index 0000000000..80845d0e65 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/dashboard/MembersDashboardVideos.ascx @@ -0,0 +1,107 @@ +<%@ Control Language="C#" AutoEventWireup="true" %> +<%@ Register Assembly="controls" Namespace="umbraco.uicontrols" TagPrefix="umb" %> +<%@ Register Assembly="ClientDependency.Core" Namespace="ClientDependency.Core.Controls" TagPrefix="umb" %> + + + + + + +
+

Watch and learn

+ Videos +

Hours of Umbraco training videos are only a click away

+

Want to master Umbraco Members? Spend a couple of minutes learning some best practices by watching one of these videos about using Umbraco. And visit umbraco.tv for even more Umbraco videos

+

To get you started:

+
Loading...
+
\ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco/dashboard/SettingsDashboardIntro.ascx b/src/Umbraco.Web.UI/umbraco/dashboard/SettingsDashboardIntro.ascx new file mode 100644 index 0000000000..e9e24dde8a --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/dashboard/SettingsDashboardIntro.ascx @@ -0,0 +1,27 @@ +<%@ Control Language="C#" AutoEventWireup="true" %> +<%@ Register Assembly="controls" Namespace="umbraco.uicontrols" TagPrefix="umb" %> +<%@ Register Assembly="ClientDependency.Core" Namespace="ClientDependency.Core.Controls" TagPrefix="umb" %> + + + +
+

Start here

+ Umbraco +

This section contains the building blocks for your Umbraco site

+

Follow the below links to find out more about working with the items in the Setings section:

+

Find out more:

+
+
+
+ +
+
+
+
diff --git a/src/Umbraco.Web.UI/umbraco/dashboard/SettingsDashboardVideos.ascx b/src/Umbraco.Web.UI/umbraco/dashboard/SettingsDashboardVideos.ascx new file mode 100644 index 0000000000..4a7a1c1e38 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/dashboard/SettingsDashboardVideos.ascx @@ -0,0 +1,107 @@ +<%@ Control Language="C#" AutoEventWireup="true" %> +<%@ Register Assembly="controls" Namespace="umbraco.uicontrols" TagPrefix="umb" %> +<%@ Register Assembly="ClientDependency.Core" Namespace="ClientDependency.Core.Controls" TagPrefix="umb" %> + + + + + + +
+

Watch and learn

+ Videos +

Hours of Umbraco training videos are only a click away

+

Want to master Umbraco? Spend a couple of minutes learning some best practices by watching one of these videos about using Umbraco. And visit umbraco.tv for even more Umbraco videos

+

To get you started:

+
Loading...
+
\ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco/dashboard/StartupDashboardIntro.ascx b/src/Umbraco.Web.UI/umbraco/dashboard/StartupDashboardIntro.ascx new file mode 100644 index 0000000000..5b12233286 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/dashboard/StartupDashboardIntro.ascx @@ -0,0 +1,45 @@ +<%@ Control Language="C#" AutoEventWireup="true" %> +<%@ Register Assembly="controls" Namespace="umbraco.uicontrols" TagPrefix="umb" %> +<%@ Register Assembly="ClientDependency.Core" Namespace="ClientDependency.Core.Controls" TagPrefix="umb" %> + + + +
+

Start Here

+ Umbraco +

Thank you for choosing Umbraco!

+

We think this could be the beginning of something beautiful. You have made a great choice, to help you get started here are some links to addtional information:

+

Find out more:

+
+
+
+

New to Umbraco

+ +
+
+

Go further

+ +
+
+

Get support

+ +
+
+
+
diff --git a/src/Umbraco.Web.UI/umbraco/dashboard/StartupDashboardKits.ascx b/src/Umbraco.Web.UI/umbraco/dashboard/StartupDashboardKits.ascx new file mode 100644 index 0000000000..d7255afd4f --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/dashboard/StartupDashboardKits.ascx @@ -0,0 +1,25 @@ +<%@ Control Language="C#" AutoEventWireup="true" %> +<%@ Register Assembly="controls" Namespace="umbraco.uicontrols" TagPrefix="umb" %> +<%@ Register Assembly="ClientDependency.Core" Namespace="ClientDependency.Core.Controls" TagPrefix="umb" %> + + + +
+

Make it look great

+ Umbraco Starter Kits Rock! +

Install a Starter Site and Skin

+

If you haven't already installed one of our Starter Kits, we think you should do that now. This is one of the best ways to start working with Umbraco. After you install a Starter Kit, you can select a skin to make it look great and customize the kit to your liking.

+

Starter Kits:

+
+
+
+ +
+
+
+
\ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco/dashboard/StartupDashboardVideos.ascx b/src/Umbraco.Web.UI/umbraco/dashboard/StartupDashboardVideos.ascx new file mode 100644 index 0000000000..c139c0931c --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/dashboard/StartupDashboardVideos.ascx @@ -0,0 +1,106 @@ +<%@ Control Language="C#" AutoEventWireup="true" %> +<%@ Register Assembly="controls" Namespace="umbraco.uicontrols" TagPrefix="umb" %> +<%@ Register Assembly="ClientDependency.Core" Namespace="ClientDependency.Core.Controls" TagPrefix="umb" %> + + + + + + +
+

Watch and learn

+ Videos +

Hours of Umbraco training videos are only a click away

+

Want to master Umbraco? Spend a couple of minutes learning some best practices by watching one of these videos about using Umbraco. And visit umbraco.tv for even more Umbraco videos

+

To get you started:

+
Loading...
+
\ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco/webservices/tagService.asmx b/src/Umbraco.Web.UI/umbraco/webservices/tagService.asmx new file mode 100644 index 0000000000..c83c8c7a5c --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/webservices/tagService.asmx @@ -0,0 +1 @@ +<%@ WebService Language="C#" CodeBehind="tagService.asmx.cs" Class="umbracoTags.webservice.tagService" %> diff --git a/src/Umbraco.Web.UI/umbraco/webservices/ultimatePickerAutoSuggest.asmx b/src/Umbraco.Web.UI/umbraco/webservices/ultimatePickerAutoSuggest.asmx new file mode 100644 index 0000000000..0d8a23409d --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/webservices/ultimatePickerAutoSuggest.asmx @@ -0,0 +1 @@ +<%@ WebService Language="C#" CodeBehind="ultimatePickerAutoSuggest.asmx.cs" Class="umbraco.presentation.umbraco.webservices.ultimatePickerAutoSuggest" %> diff --git a/src/Umbraco.Web/DocumentExtensions.cs b/src/Umbraco.Web/DocumentExtensions.cs new file mode 100644 index 0000000000..bf63757645 --- /dev/null +++ b/src/Umbraco.Web/DocumentExtensions.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using Umbraco.Core.Models; +using Umbraco.Web.Routing; +using umbraco.cms.businesslogic; +using Umbraco.Core; + +namespace Umbraco.Web +{ + /// + /// Extension methods for IDocument + /// + /// + /// These methods exist in the web project as we need access to web based classes like NiceUrl provider + /// which is why they cannot exist in the Core project. + /// + public static class DocumentExtensions + { + + /// + /// Returns a DataTable object for the IDocument + /// + /// + /// + /// + public static DataTable ChildrenAsTable(this IDocument d, string nodeTypeAliasFilter = "") + { + return GenerateDataTable(d, nodeTypeAliasFilter); + } + + /// + /// Generates the DataTable for the IDocument + /// + /// + /// + /// + private static DataTable GenerateDataTable(IDocument node, string nodeTypeAliasFilter = "") + { + var firstNode = nodeTypeAliasFilter.IsNullOrWhiteSpace() + ? node.Children.Any() + ? node.Children.ElementAt(0) + : null + : node.Children.FirstOrDefault(x => x.DocumentTypeAlias == nodeTypeAliasFilter); + if (firstNode == null) + return new DataTable(); //no children found + + var urlProvider = UmbracoContext.Current.RoutingContext.NiceUrlProvider; + + //use new utility class to create table so that we don't have to maintain code in many places, just one + var dt = Umbraco.Core.DataTableExtensions.GenerateDataTable( + //pass in the alias of the first child node since this is the node type we're rendering headers for + firstNode.DocumentTypeAlias, + //pass in the callback to extract the Dictionary of all defined aliases to their names + alias => GetPropertyAliasesAndNames(alias), + //pass in a callback to populate the datatable, yup its a bit ugly but it's already legacy and we just want to maintain code in one place. + () => + { + //create all row data + var tableData = Umbraco.Core.DataTableExtensions.CreateTableData(); + //loop through each child and create row data for it + foreach (var n in node.Children) + { + if (!nodeTypeAliasFilter.IsNullOrWhiteSpace()) + { + if (n.DocumentTypeAlias != nodeTypeAliasFilter) + continue; //skip this one, it doesn't match the filter + } + + var standardVals = new Dictionary() + { + {"Id", n.Id}, + {"NodeName", n.Name}, + {"NodeTypeAlias", n.DocumentTypeAlias}, + {"CreateDate", n.CreateDate}, + {"UpdateDate", n.UpdateDate}, + {"CreatorName", n.CreatorName}, + {"WriterName", n.WriterName}, + {"Url", urlProvider.GetNiceUrl(n.Id)} + }; + var userVals = new Dictionary(); + foreach (var p in from IDocumentProperty p in n.Properties where p.Value != null select p) + { + userVals[p.Alias] = p.Value; + } + //add the row data + Umbraco.Core.DataTableExtensions.AddRowData(tableData, standardVals, userVals); + } + return tableData; + } + ); + return dt; + } + + private static Func> _getPropertyAliasesAndNames; + + /// + /// This is used only for unit tests to set the delegate to look up aliases/names dictionary of a content type + /// + internal static Func> GetPropertyAliasesAndNames + { + get + { + return _getPropertyAliasesAndNames ?? (_getPropertyAliasesAndNames = alias => + { + var userFields = ContentType.GetAliasesAndNames(alias); + //ensure the standard fields are there + var allFields = new Dictionary() + { + {"Id", "Id"}, + {"NodeName", "NodeName"}, + {"NodeTypeAlias", "NodeTypeAlias"}, + {"CreateDate", "CreateDate"}, + {"UpdateDate", "UpdateDate"}, + {"CreatorName", "CreatorName"}, + {"WriterName", "WriterName"}, + {"Url", "Url"} + }; + foreach (var f in userFields.Where(f => !allFields.ContainsKey(f.Key))) + { + allFields.Add(f.Key, f.Value); + } + return allFields; + }); + } + set { _getPropertyAliasesAndNames = value; } + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index c7c441574f..e9b3d54ddd 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -245,6 +245,7 @@ + @@ -276,6 +277,12 @@ ASPXCodeBehind + + ASPXCodeBehind + + + ASPXCodeBehind + @@ -1238,20 +1245,6 @@ sendToTranslation.aspx - - treePicker.aspx - ASPXCodeBehind - - - treePicker.aspx - - - umbracoField.aspx - ASPXCodeBehind - - - umbracoField.aspx - uploadImage.aspx ASPXCodeBehind @@ -1933,10 +1926,6 @@ - - - ASPXCodeBehind - diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/nodeFactory/Node.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/nodeFactory/Node.cs index 2db509fa87..001219423b 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/nodeFactory/Node.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/nodeFactory/Node.cs @@ -359,46 +359,49 @@ namespace umbraco.NodeFactory public DataTable ChildrenAsTable() { - return Children.Count > 0 ? GenerateDataTable(Children[0]) : new DataTable(); + return GenerateDataTable(this); } public DataTable ChildrenAsTable(string nodeTypeAliasFilter) { - if (Children.Count > 0) - { - - Node Firstnode = null; - Boolean nodeFound = false; - foreach (Node n in Children) - { - if (n.NodeTypeAlias == nodeTypeAliasFilter && !nodeFound) - { - Firstnode = n; - nodeFound = true; - break; - } - } - - if (nodeFound) - { - return GenerateDataTable(Firstnode); - } - return new DataTable(); - } - return new DataTable(); + return GenerateDataTable(this, nodeTypeAliasFilter); } - private DataTable GenerateDataTable(INode node) + private DataTable GenerateDataTable(INode node, string nodeTypeAliasFilter = "") { + var firstNode = nodeTypeAliasFilter.IsNullOrWhiteSpace() + ? node.ChildrenAsList.Any() + ? node.ChildrenAsList[0] + : null + : node.ChildrenAsList.FirstOrDefault(x => x.NodeTypeAlias == nodeTypeAliasFilter); + if (firstNode == null) + return new DataTable(); //no children found + //use new utility class to create table so that we don't have to maintain code in many places, just one var dt = Umbraco.Core.DataTableExtensions.GenerateDataTable( - //pass in the alias - node.NodeTypeAlias, - //pass in the callback to extract the Dictionary of user defined aliases to their names + //pass in the alias of the first child node since this is the node type we're rendering headers for + firstNode.NodeTypeAlias, + //pass in the callback to extract the Dictionary of column aliases to names alias => { - var ct = ContentType.GetByAlias(alias); - return ct.PropertyTypes.ToDictionary(x => x.Alias, x => x.Name); + var userFields = ContentType.GetAliasesAndNames(alias); + //ensure the standard fields are there + var allFields = new Dictionary() + { + {"Id", "Id"}, + {"NodeName", "NodeName"}, + {"NodeTypeAlias", "NodeTypeAlias"}, + {"CreateDate", "CreateDate"}, + {"UpdateDate", "UpdateDate"}, + {"CreatorName", "CreatorName"}, + {"WriterName", "WriterName"}, + {"Url", "Url"} + }; + foreach (var f in userFields.Where(f => !allFields.ContainsKey(f.Key))) + { + allFields.Add(f.Key, f.Value); + } + return allFields; }, //pass in a callback to populate the datatable, yup its a bit ugly but it's already legacy and we just want to maintain code in one place. () => @@ -408,6 +411,12 @@ namespace umbraco.NodeFactory //loop through each child and create row data for it foreach (Node n in Children) { + if (!nodeTypeAliasFilter.IsNullOrWhiteSpace()) + { + if (n.NodeTypeAlias != nodeTypeAliasFilter) + continue; //skip this one, it doesn't match the filter + } + var standardVals = new Dictionary() { {"Id", n.Id}, diff --git a/src/umbraco.MacroEngines/RazorDynamicNode/DynamicDocumentExtensions.cs b/src/umbraco.MacroEngines/RazorDynamicNode/DynamicDocumentExtensions.cs index 055d4cf416..66cd5b8c89 100644 --- a/src/umbraco.MacroEngines/RazorDynamicNode/DynamicDocumentExtensions.cs +++ b/src/umbraco.MacroEngines/RazorDynamicNode/DynamicDocumentExtensions.cs @@ -26,6 +26,9 @@ namespace umbraco.MacroEngines.Library return node; } + /// + /// Internal custom INode class used for conversions from DynamicDocument + /// private class ConvertedNode : INode { private readonly DynamicDocument _doc; diff --git a/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNodeList.cs b/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNodeList.cs index 3dde965e0f..8872a351b1 100644 --- a/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNodeList.cs +++ b/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNodeList.cs @@ -15,11 +15,13 @@ namespace umbraco.MacroEngines { public class DynamicNodeList : DynamicObject, IEnumerable { - public List Items; - public List get_Items() - { - return Items; - } + public List Items; + + [Obsolete("Use the Items property instead")] + public List get_Items() + { + return Items; + } public DynamicNodeList() { diff --git a/src/umbraco.cms/businesslogic/ContentType.cs b/src/umbraco.cms/businesslogic/ContentType.cs index 6b83201bd5..befaa03556 100644 --- a/src/umbraco.cms/businesslogic/ContentType.cs +++ b/src/umbraco.cms/businesslogic/ContentType.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; using System.Runtime.CompilerServices; @@ -100,8 +101,36 @@ namespace umbraco.cms.businesslogic #region Static Methods + /// + /// Used for cache so we don't have to lookup column names all the time, this is actually only used for the ChildrenAsTable methods + /// + private static readonly ConcurrentDictionary> AliasToNames = new ConcurrentDictionary>(); + private static Dictionary, Guid> _propertyTypeCache = new Dictionary, Guid>(); - public static void RemoveFromDataTypeCache(string contentTypeAlias) + + /// + /// Returns a content type's columns alias -> name mapping + /// + /// + /// + /// + /// This is currently only used for ChildrenAsTable methods, caching is moved here instead of in the app logic so we can clear the cache + /// + internal static IDictionary GetAliasesAndNames(string contentTypeAlias) + { + IDictionary cached; + if (AliasToNames.TryGetValue(contentTypeAlias, out cached)) + { + return cached; + } + + var ct = ContentType.GetByAlias(contentTypeAlias); + var userFields = ct.PropertyTypes.ToDictionary(x => x.Alias, x => x.Name); + AliasToNames.TryAdd(contentTypeAlias, userFields); + return userFields; + } + + public static void RemoveFromDataTypeCache(string contentTypeAlias) { lock (_propertyTypeCache) { @@ -116,8 +145,10 @@ namespace umbraco.cms.businesslogic foreach (Tuple key in toDelete) { _propertyTypeCache.Remove(key); - } + } } + //don't put lock around this as it is ConcurrentDictionary. + AliasToNames.Clear(); } public static Guid GetDataType(string contentTypeAlias, string propertyTypeAlias) {