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") %>
+

+
+ <%=umbraco.ui.Text("changePasswordDescription") %>
+
+
+
+
+ -
+
+ <%=umbraco.ui.Text("username") %>:
+ <%=umbraco.BusinessLogic.User.GetCurrent().Name%>
+
+
+ -
+
+ <%=umbraco.ui.Text("passwordEnterNew") %>:
+
+ *
+
+
+ -
+
+ <%=umbraco.ui.Text("passwordConfirm") %>:
+
+ *
+ <%=umbraco.ui.Text("passwordMismatch") %>
+
+
+
+
+
+
+
+
+ <%=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
+

+
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.
+
+
\ 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
+

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

+
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")%>
+

+
+
+ <%# 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
+

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

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

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

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

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

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

+
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:
+
+
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
+

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

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