From b3b2b5b9eeaf083d5d705499439aee72c942ecb6 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 30 Jul 2013 13:29:05 +1000 Subject: [PATCH] Implemented much more of the new tree api structure. Have converted most of the content tree over to use it. --- src/Umbraco.Core/Constants-Applications.cs | 21 ++ src/Umbraco.Core/PluginManager.cs | 1 + src/Umbraco.Core/StringExtensions.cs | 10 + .../src/common/services/tree.service.js | 5 +- .../src/views/common/navigation.controller.js | 12 +- src/Umbraco.Web.UI/config/trees.config | 6 +- src/Umbraco.Web/PluginManagerExtensions.cs | 13 + .../Trees/ApplicationTreeController.cs | 79 +++--- .../Trees/ApplicationTreeExtensions.cs | 6 +- .../Trees/ApplicationTreeRegistrar.cs | 90 ++++++ .../Trees/ContentTreeController.cs | 146 ++++++++++ ...iController.cs => LegacyTreeController.cs} | 204 +++++++------- .../Trees/LegacyTreeDataConverter.cs | 8 +- src/Umbraco.Web/Trees/MenuItem.cs | 10 +- src/Umbraco.Web/Trees/MenuItemCollection.cs | 26 +- .../Trees/TestTreeApiController.cs | 28 -- src/Umbraco.Web/Trees/TreeApiController.cs | 264 +++++++----------- src/Umbraco.Web/Trees/TreeAttribute.cs | 46 +++ src/Umbraco.Web/Trees/TreeNode.cs | 36 ++- src/Umbraco.Web/Trees/TreeNodeExtensions.cs | 17 ++ src/Umbraco.Web/Umbraco.Web.csproj | 7 +- .../ApplicationTreeRegistrar.cs | 51 +--- src/umbraco.businesslogic/TreeAttribute.cs | 5 + 23 files changed, 664 insertions(+), 427 deletions(-) create mode 100644 src/Umbraco.Web/Trees/ApplicationTreeRegistrar.cs create mode 100644 src/Umbraco.Web/Trees/ContentTreeController.cs rename src/Umbraco.Web/Trees/{LegacyTreeApiController.cs => LegacyTreeController.cs} (90%) delete mode 100644 src/Umbraco.Web/Trees/TestTreeApiController.cs create mode 100644 src/Umbraco.Web/Trees/TreeAttribute.cs create mode 100644 src/Umbraco.Web/Trees/TreeNodeExtensions.cs diff --git a/src/Umbraco.Core/Constants-Applications.cs b/src/Umbraco.Core/Constants-Applications.cs index dec9d2fb16..0efa678d4e 100644 --- a/src/Umbraco.Core/Constants-Applications.cs +++ b/src/Umbraco.Core/Constants-Applications.cs @@ -42,5 +42,26 @@ /// public const string Users = "users"; } + + /// + /// Defines the alias identifiers for Umbraco's core trees. + /// + public static class Trees + { + /// + /// alias for the content tree. + /// + public const string Content = "content"; + + /// + /// alias for the media tree. + /// + public const string Media = "media"; + + //TODO: Fill in the rest! + + } } + + } \ No newline at end of file diff --git a/src/Umbraco.Core/PluginManager.cs b/src/Umbraco.Core/PluginManager.cs index 7b941c1f00..031d4f587d 100644 --- a/src/Umbraco.Core/PluginManager.cs +++ b/src/Umbraco.Core/PluginManager.cs @@ -424,6 +424,7 @@ namespace Umbraco.Core private readonly HashSet _types = new HashSet(); private IEnumerable _assemblies; + /// /// Returns all found property editors /// diff --git a/src/Umbraco.Core/StringExtensions.cs b/src/Umbraco.Core/StringExtensions.cs index dd4ced35d9..f2c976d144 100644 --- a/src/Umbraco.Core/StringExtensions.cs +++ b/src/Umbraco.Core/StringExtensions.cs @@ -436,6 +436,16 @@ namespace Umbraco.Core return String.Format(CultureInfo.InvariantCulture, format, args); } + /// + /// Converts an integer to an invariant formatted string + /// + /// + /// + public static string ToInvariantString(this int str) + { + return str.ToString(CultureInfo.InvariantCulture); + } + /// /// Compares 2 strings with invariant culture and case ignored /// diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js index e7ecf60a97..fde4494d1e 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js @@ -18,7 +18,10 @@ function treeService($q, treeResource, iconHelper) { var childLevel = (level ? level : 1); for (var i = 0; i < treeNodes.length; i++) { treeNodes[i].level = childLevel; - treeNodes[i].view = section + "/edit/" + treeNodes[i].id; + //if there is not route path specified, then set it automatically + if (!treeNodes[i].routePath) { + treeNodes[i].routePath = section + "/edit/" + treeNodes[i].id; + } treeNodes[i].parent = parentNode; } } diff --git a/src/Umbraco.Web.UI.Client/src/views/common/navigation.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/navigation.controller.js index f4e6b62b25..6a0516e495 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/navigation.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/navigation.controller.js @@ -46,15 +46,15 @@ function NavigationController($scope,$rootScope, $location, $log, navigationServ var n = args.node; //here we need to check for some legacy tree code - if (n.jsClickCallback && n.jsClickCallback !== "") { + if (n.metaData && n.metaData["jsClickCallback"] && angular.isString(n.metaData["jsClickCallback"]) && n.metaData["jsClickCallback"] !== "") { //this is a legacy tree node! var jsPrefix = "javascript:"; var js; - if (n.jsClickCallback.startsWith(jsPrefix)) { - js = n.jsClickCallback.substr(jsPrefix.length); + if (n.metaData["jsClickCallback"].startsWith(jsPrefix)) { + js = n.metaData["jsClickCallback"].substr(jsPrefix.length); } else { - js = n.jsClickCallback; + js = n.metaData["jsClickCallback"]; } try { var func = eval(js); @@ -69,9 +69,9 @@ function NavigationController($scope,$rootScope, $location, $log, navigationServ } else { //add action to the history service - historyService.add({name: n.name, link: n.view, icon: n.icon}); + historyService.add({ name: n.name, link: n.routePath, icon: n.icon }); //not legacy, lets just set the route value and clear the query string if there is one. - $location.path(n.view).search(null); + $location.path(n.routePath).search(null); } }); diff --git a/src/Umbraco.Web.UI/config/trees.config b/src/Umbraco.Web.UI/config/trees.config index 6834440077..d8d4957c6d 100644 --- a/src/Umbraco.Web.UI/config/trees.config +++ b/src/Umbraco.Web.UI/config/trees.config @@ -1,8 +1,8 @@  - - + @@ -39,4 +39,6 @@ + + \ No newline at end of file diff --git a/src/Umbraco.Web/PluginManagerExtensions.cs b/src/Umbraco.Web/PluginManagerExtensions.cs index ff331fe8d9..6196e00fd3 100644 --- a/src/Umbraco.Web/PluginManagerExtensions.cs +++ b/src/Umbraco.Web/PluginManagerExtensions.cs @@ -5,6 +5,7 @@ using Umbraco.Core; using Umbraco.Core.Media; using Umbraco.Web.Mvc; using Umbraco.Web.Routing; +using Umbraco.Web.Trees; using Umbraco.Web.WebApi; using umbraco; using umbraco.interfaces; @@ -16,6 +17,18 @@ namespace Umbraco.Web /// public static class PluginManagerExtensions { + + /// + /// Returns all available TreeApiController's in application that are attribute with TreeAttribute + /// + /// + /// + internal static IEnumerable ResolveAttributedTreeControllers(this PluginManager resolver) + { + //don't cache the result of this because it is only used once during app startup, caching will just add a bit more mem overhead for no reason + return resolver.ResolveTypesWithAttribute(cacheResult: false); + } + internal static IEnumerable ResolveSurfaceControllers(this PluginManager resolver) { return resolver.ResolveTypes(); diff --git a/src/Umbraco.Web/Trees/ApplicationTreeController.cs b/src/Umbraco.Web/Trees/ApplicationTreeController.cs index 0b5cd3eb5a..41509062e3 100644 --- a/src/Umbraco.Web/Trees/ApplicationTreeController.cs +++ b/src/Umbraco.Web/Trees/ApplicationTreeController.cs @@ -10,6 +10,7 @@ using Umbraco.Core.Services; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Filters; +using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.Trees { @@ -39,28 +40,24 @@ namespace Umbraco.Web.Trees { if (application == null) throw new ArgumentNullException("application"); - var rootId = Core.Constants.System.Root.ToString(CultureInfo.InvariantCulture); + var rootId = Constants.System.Root.ToString(CultureInfo.InvariantCulture); //find all tree definitions that have the current application alias var appTrees = ApplicationContext.Current.Services.ApplicationTreeService.GetApplicationTrees(application).Where(x => x.Initialize).ToArray(); if (appTrees.Count() == 1) - { - return new SectionRootNode( - rootId, - Url.GetUmbracoApiService("GetMenu", rootId) - + "&parentId=" + rootId - + "&treeType=" + application - + "§ion=" + application) - { - Children = GetNodeCollection(appTrees.Single(), "-1", queryStrings) - }; + { + return GetRootForSingleAppTree( + appTrees.Single(), + Constants.System.Root.ToString(CultureInfo.InvariantCulture), + queryStrings, + application); } var collection = new TreeNodeCollection(); foreach (var tree in appTrees) { //return the root nodes for each tree in the app - var rootNode = GetRoot(tree, queryStrings); + var rootNode = GetRootForMultipleAppTree(tree, queryStrings); collection.Add(rootNode); } @@ -71,27 +68,13 @@ namespace Umbraco.Web.Trees }; } - ///// - ///// Returns the tree data for a specific tree for the children of the id - ///// - ///// - ///// - ///// - ///// - //[HttpQueryStringFilter("queryStrings")] - //public TreeNodeCollection GetTreeData(string treeType, string id, FormDataCollection queryStrings) - //{ - // if (treeType == null) throw new ArgumentNullException("treeType"); - - // //get the configured tree - // var foundConfigTree = ApplicationTreeCollection.GetByAlias(treeType); - // if (foundConfigTree == null) - // throw new InstanceNotFoundException("Could not find tree of type " + treeType + " in the trees.config"); - - // return GetNodeCollection(foundConfigTree, id, queryStrings); - //} - - private TreeNode GetRoot(ApplicationTree configTree, FormDataCollection queryStrings) + /// + /// Get the root node for an application with multiple trees + /// + /// + /// + /// + private TreeNode GetRootForMultipleAppTree(ApplicationTree configTree, FormDataCollection queryStrings) { if (configTree == null) throw new ArgumentNullException("configTree"); var byControllerAttempt = configTree.TryGetRootNodeFromControllerTree(queryStrings, ControllerContext, Request); @@ -110,24 +93,46 @@ namespace Umbraco.Web.Trees } /// - /// Get the node collection for the tree, try loading from new controllers first, then from legacy trees + /// Get the root node for an application with one tree /// /// /// /// /// - private TreeNodeCollection GetNodeCollection(ApplicationTree configTree, string id, FormDataCollection queryStrings) + private SectionRootNode GetRootForSingleAppTree(ApplicationTree configTree, string id, FormDataCollection queryStrings, string application) { + var rootId = Constants.System.Root.ToString(CultureInfo.InvariantCulture); if (configTree == null) throw new ArgumentNullException("configTree"); var byControllerAttempt = configTree.TryLoadFromControllerTree(id, queryStrings, ControllerContext, Request); if (byControllerAttempt.Success) { - return byControllerAttempt.Result; + var rootNode = configTree.TryGetRootNodeFromControllerTree(queryStrings, ControllerContext, Request); + if (rootNode.Success == false) + { + //This should really never happen if we've successfully got the children above. + throw new InvalidOperationException("Could not create root node for tree " + configTree.Alias); + } + + return new SectionRootNode( + rootId, + rootNode.Result.MenuUrl) + { + Children = byControllerAttempt.Result + }; + } var legacyAttempt = configTree.TryLoadFromLegacyTree(id, queryStrings, Url, configTree.ApplicationAlias); if (legacyAttempt.Success) { - return legacyAttempt.Result; + return new SectionRootNode( + rootId, + Url.GetUmbracoApiService("GetMenu", rootId) + + "&parentId=" + rootId + + "&treeType=" + application + + "§ion=" + application) + { + Children = legacyAttempt.Result + }; } throw new ApplicationException("Could not render a tree for type " + configTree.Alias); diff --git a/src/Umbraco.Web/Trees/ApplicationTreeExtensions.cs b/src/Umbraco.Web/Trees/ApplicationTreeExtensions.cs index 62812ec8e0..b8475ac059 100644 --- a/src/Umbraco.Web/Trees/ApplicationTreeExtensions.cs +++ b/src/Umbraco.Web/Trees/ApplicationTreeExtensions.cs @@ -50,10 +50,10 @@ namespace Umbraco.Web.Trees instance.ControllerContext = controllerContext; instance.Request = request; //return the root - var nodes = instance.GetNodes(Constants.System.Root.ToString(CultureInfo.InvariantCulture), formCollection); - return nodes.Any() == false + var node = instance.GetRootNode(formCollection); + return node == null ? new Attempt(new InvalidOperationException("Could not return a root node for tree " + appTree.Type)) - : new Attempt(true, nodes.First()); + : new Attempt(true, node); } internal static Attempt TryLoadFromControllerTree(this ApplicationTree appTree, string id, FormDataCollection formCollection, HttpControllerContext controllerContext, HttpRequestMessage request) diff --git a/src/Umbraco.Web/Trees/ApplicationTreeRegistrar.cs b/src/Umbraco.Web/Trees/ApplicationTreeRegistrar.cs new file mode 100644 index 0000000000..d7c0db9a13 --- /dev/null +++ b/src/Umbraco.Web/Trees/ApplicationTreeRegistrar.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; +using Umbraco.Core; +using umbraco.businesslogic; + +namespace Umbraco.Web.Trees +{ + /// + /// A startup handler for putting the tree config in the config file based on attributes found + /// + public sealed class ApplicationTreeRegistrar : ApplicationEventHandler + { + protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext) + { + ScanTrees(applicationContext); + } + + /// + /// Scans for all attributed trees and ensures they exist in the tree xml + /// + private static void ScanTrees(ApplicationContext applicationContext) + { + applicationContext.Services.ApplicationTreeService.LoadXml(doc => + { + var added = new List(); + + // Load all Controller Trees by attribute and add them to the XML config + // we also need to make sure that any alias added with the new trees is not also added + // with the legacy trees. + var types = PluginManager.Current.ResolveAttributedTreeControllers(); + + var items = types + .Select(x => + new Tuple(x, x.GetCustomAttributes(false).Single())) + .Where(x => applicationContext.Services.ApplicationTreeService.GetByAlias(x.Item2.Alias) == null); + + foreach (var tuple in items) + { + var type = tuple.Item1; + var attr = tuple.Item2; + + //Add the new tree that doesn't exist in the config that was found by type finding + + doc.Root.Add(new XElement("add", + new XAttribute("initialize", attr.Initialize), + new XAttribute("sortOrder", attr.SortOrder), + new XAttribute("alias", attr.Alias), + new XAttribute("application", attr.ApplicationAlias), + new XAttribute("title", attr.Title), + new XAttribute("iconClosed", attr.IconClosed), + new XAttribute("iconOpen", attr.IconOpen), + new XAttribute("type", type.GetFullNameWithAssembly()))); + + added.Add(attr.Alias); + } + + + // Load all LEGACY Trees by attribute and add them to the XML config + var legacyTreeTypes = PluginManager.Current.ResolveAttributedTrees(); + + var legacyItems = legacyTreeTypes + .Select(x => + new Tuple(x, x.GetCustomAttributes(false).Single())) + .Where(x => applicationContext.Services.ApplicationTreeService.GetByAlias(x.Item2.Alias) == null + //make sure the legacy tree isn't added on top of the controller tree! + && !added.InvariantContains(x.Item2.Alias)); + + foreach (var tuple in legacyItems) + { + var type = tuple.Item1; + var attr = tuple.Item2; + + //Add the new tree that doesn't exist in the config that was found by type finding + doc.Root.Add(new XElement("add", + new XAttribute("initialize", attr.Initialize), + new XAttribute("sortOrder", attr.SortOrder), + new XAttribute("alias", attr.Alias), + new XAttribute("application", attr.ApplicationAlias), + new XAttribute("title", attr.Title), + new XAttribute("iconClosed", attr.IconClosed), + new XAttribute("iconOpen", attr.IconOpen), + new XAttribute("type", type.GetFullNameWithAssembly()))); + } + + }, true); + } + } +} diff --git a/src/Umbraco.Web/Trees/ContentTreeController.cs b/src/Umbraco.Web/Trees/ContentTreeController.cs new file mode 100644 index 0000000000..a1fbdabaeb --- /dev/null +++ b/src/Umbraco.Web/Trees/ContentTreeController.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Net.Http.Formatting; +using System.Web.Http; +using Umbraco.Core; +using Umbraco.Core.Models; +using umbraco.BusinessLogic.Actions; +using umbraco.businesslogic; +using umbraco.interfaces; + +namespace Umbraco.Web.Trees +{ + public abstract class ContentTreeControllerBase : TreeApiController + { + /// + /// Based on the allowed actions, this will filter the ones that the current user is allowed + /// + /// + /// + /// + protected MenuItemCollection GetUserAllowedMenuItems(IEnumerable allMenuItems, IEnumerable userAllowedMenuItems) + { + var userAllowedActions = userAllowedMenuItems.Where(x => x.Action != null).Select(x => x.Action).ToArray(); + return new MenuItemCollection(allMenuItems.Where( + a => (a.Action == null + || a.Action.CanBePermissionAssigned == false + || (a.Action.CanBePermissionAssigned && userAllowedActions.Contains(a.Action))))); + } + + internal MenuItemCollection GetUserMenuItemsForNode(UmbracoEntity dd) + { + var actions = global::umbraco.BusinessLogic.Actions.Action.FromString(UmbracoUser.GetPermissions(dd.Path)); + + // A user is allowed to delete their own stuff + if (dd.CreatorId == UmbracoUser.Id && actions.Contains(ActionDelete.Instance) == false) + actions.Add(ActionDelete.Instance); + + return new MenuItemCollection(actions.Select(x => new MenuItem(x))); + } + + } + + [Tree(Constants.Applications.Content, Constants.Trees.Content, "Content")] + public class ContentTreeController : ContentTreeControllerBase + { + protected override TreeNode CreateRootNode(FormDataCollection queryStrings) + { + //TODO: We need to implement security checks here and the user's start node! + + return base.CreateRootNode(queryStrings); + } + + protected override TreeNodeCollection GetTreeData(string id, FormDataCollection queryStrings) + { + int iid; + if (int.TryParse(id, out iid) == false) + { + throw new InvalidCastException("The id for the content tree must be an integer"); + } + + var nodes = new TreeNodeCollection(); + var entities = Services.EntityService.GetChildren(iid, UmbracoObjectTypes.Document).ToArray(); + foreach (var entity in entities) + { + //TODO: We need to implement security checks here! + + var e = (UmbracoEntity)entity; + nodes.Add( + CreateTreeNode( + e.Id.ToInvariantString(), + queryStrings, + e.Name, + e.ContentTypeIcon, + e.HasChildren)); + } + return nodes; + } + + protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings) + { + var menu = new MenuItemCollection(); + + if (id == Constants.System.Root.ToInvariantString()) + { + // we need to get the default permissions as you can't set permissions on the very root node + var nodeActions = global::umbraco.BusinessLogic.Actions.Action.FromString( + UmbracoUser.GetPermissions(Constants.System.Root.ToInvariantString())) + .Select(x => new MenuItem(x)); + + menu.AddMenuItem(); + menu.AddMenuItem(); + var allowedMenu = GetUserAllowedMenuItems(menu, nodeActions); + + if (allowedMenu.Any()) + { + allowedMenu.Last().SeperatorBefore = true; + } + + // default actions for all users + allowedMenu.AddMenuItem(); + allowedMenu.AddMenuItem(true); + return allowedMenu; + } + + //return a normal node menu: + int iid; + if (int.TryParse(id, out iid) == false) + { + throw new InvalidOperationException("The Id for a content item must be an integer"); + } + var item = Services.EntityService.Get(iid, UmbracoObjectTypes.Document); + if (item == null) + { + throw new HttpResponseException(HttpStatusCode.NotFound); + } + + return GetUserAllowedMenuItems( + CreateAllowedActions(), + GetUserMenuItemsForNode((UmbracoEntity) item)); + } + + protected IEnumerable CreateAllowedActions() + { + var menu = new MenuItemCollection(); + menu.AddMenuItem(); + menu.AddMenuItem(true); + menu.AddMenuItem(true); + menu.AddMenuItem(); + menu.AddMenuItem(true); + menu.AddMenuItem(); + menu.AddMenuItem(true); + menu.AddMenuItem(); + menu.AddMenuItem(); + menu.AddMenuItem(); + menu.AddMenuItem(true); + menu.AddMenuItem(true); + menu.AddMenuItem(true); + menu.AddMenuItem(); + menu.AddMenuItem(true); + return menu; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Trees/LegacyTreeApiController.cs b/src/Umbraco.Web/Trees/LegacyTreeController.cs similarity index 90% rename from src/Umbraco.Web/Trees/LegacyTreeApiController.cs rename to src/Umbraco.Web/Trees/LegacyTreeController.cs index 858f721917..d89496c55f 100644 --- a/src/Umbraco.Web/Trees/LegacyTreeApiController.cs +++ b/src/Umbraco.Web/Trees/LegacyTreeController.cs @@ -1,103 +1,103 @@ -using System; -using System.Globalization; -using System.Linq; -using System.Net.Http.Formatting; -using Umbraco.Core.Logging; -using Umbraco.Core.Models; -using Umbraco.Core.Services; -using Umbraco.Web.Mvc; -using Umbraco.Web.WebApi; -using Umbraco.Web.WebApi.Filters; - -namespace Umbraco.Web.Trees -{ - - /// - /// This is used to output JSON from legacy trees - /// - [PluginController("UmbracoTrees")] - public class LegacyTreeApiController : UmbracoAuthorizedApiController - { - /// - /// Convert a legacy tree to a new tree result - /// - /// - /// - /// - [HttpQueryStringFilter("queryStrings")] - public TreeNodeCollection GetNodes(string id, FormDataCollection queryStrings) - { - var tree = GetTree(queryStrings); - var attempt = tree.TryLoadFromLegacyTree(id, queryStrings, Url, tree.ApplicationAlias); - if (attempt.Success == false) - { - var msg = "Could not render tree " + queryStrings.GetRequiredString("treeType") + " for node id " + id; - LogHelper.Error(msg, attempt.Error); - throw new ApplicationException(msg); - } - - return attempt.Result; - } - - /// - /// This will return the menu item collection for the tree node with the specified Id - /// - /// - /// - /// - /// - /// Due to the nature of legacy trees this means that we need to lookup the parent node, render - /// the TreeNodeCollection and then find the node we're looking for and render it's menu. - /// - [HttpQueryStringFilter("queryStrings")] - public MenuItemCollection GetMenu(string id, FormDataCollection queryStrings) - { - //get the parent id from the query strings - var parentId = queryStrings.GetRequiredString("parentId"); - var tree = GetTree(queryStrings); - - var rootIds = new[] - { - Core.Constants.System.Root.ToString(CultureInfo.InvariantCulture), - Core.Constants.System.RecycleBinContent.ToString(CultureInfo.InvariantCulture), - Core.Constants.System.RecycleBinMedia.ToString(CultureInfo.InvariantCulture) - }; - - //if the id and the parentId are both -1 then we need to get the menu for the root node - if (rootIds.Contains(id) && parentId == "-1") - { - var attempt = tree.TryGetMenuFromLegacyTreeRootNode(queryStrings, Url); - if (attempt.Success == false) - { - var msg = "Could not render menu for root node for treeType " + queryStrings.GetRequiredString("treeType"); - LogHelper.Error(msg, attempt.Error); - throw new ApplicationException(msg); - } - return attempt.Result; - } - else - { - var attempt = tree.TryGetMenuFromLegacyTreeNode(parentId, id, queryStrings, Url); - if (attempt.Success == false) - { - var msg = "Could not render menu for treeType " + queryStrings.GetRequiredString("treeType") + " for node id " + parentId; - LogHelper.Error(msg, attempt.Error); - throw new ApplicationException(msg); - } - return attempt.Result; - } - } - - private ApplicationTree GetTree(FormDataCollection queryStrings) - { - //need to ensure we have a tree type - var treeType = queryStrings.GetRequiredString("treeType"); - //now we'll look up that tree - var tree = Services.ApplicationTreeService.GetByAlias(treeType); - if (tree == null) - throw new InvalidOperationException("No tree found with alias " + treeType); - return tree; - } - - } +using System; +using System.Globalization; +using System.Linq; +using System.Net.Http.Formatting; +using Umbraco.Core.Logging; +using Umbraco.Core.Models; +using Umbraco.Core.Services; +using Umbraco.Web.Mvc; +using Umbraco.Web.WebApi; +using Umbraco.Web.WebApi.Filters; + +namespace Umbraco.Web.Trees +{ + + /// + /// This is used to output JSON from legacy trees + /// + [PluginController("UmbracoTrees")] + public class LegacyTreeController : UmbracoAuthorizedApiController + { + /// + /// Convert a legacy tree to a new tree result + /// + /// + /// + /// + [HttpQueryStringFilter("queryStrings")] + public TreeNodeCollection GetNodes(string id, FormDataCollection queryStrings) + { + var tree = GetTree(queryStrings); + var attempt = tree.TryLoadFromLegacyTree(id, queryStrings, Url, tree.ApplicationAlias); + if (attempt.Success == false) + { + var msg = "Could not render tree " + queryStrings.GetRequiredString("treeType") + " for node id " + id; + LogHelper.Error(msg, attempt.Error); + throw new ApplicationException(msg); + } + + return attempt.Result; + } + + /// + /// This will return the menu item collection for the tree node with the specified Id + /// + /// + /// + /// + /// + /// Due to the nature of legacy trees this means that we need to lookup the parent node, render + /// the TreeNodeCollection and then find the node we're looking for and render it's menu. + /// + [HttpQueryStringFilter("queryStrings")] + public MenuItemCollection GetMenu(string id, FormDataCollection queryStrings) + { + //get the parent id from the query strings + var parentId = queryStrings.GetRequiredString("parentId"); + var tree = GetTree(queryStrings); + + var rootIds = new[] + { + Core.Constants.System.Root.ToString(CultureInfo.InvariantCulture), + Core.Constants.System.RecycleBinContent.ToString(CultureInfo.InvariantCulture), + Core.Constants.System.RecycleBinMedia.ToString(CultureInfo.InvariantCulture) + }; + + //if the id and the parentId are both -1 then we need to get the menu for the root node + if (rootIds.Contains(id) && parentId == "-1") + { + var attempt = tree.TryGetMenuFromLegacyTreeRootNode(queryStrings, Url); + if (attempt.Success == false) + { + var msg = "Could not render menu for root node for treeType " + queryStrings.GetRequiredString("treeType"); + LogHelper.Error(msg, attempt.Error); + throw new ApplicationException(msg); + } + return attempt.Result; + } + else + { + var attempt = tree.TryGetMenuFromLegacyTreeNode(parentId, id, queryStrings, Url); + if (attempt.Success == false) + { + var msg = "Could not render menu for treeType " + queryStrings.GetRequiredString("treeType") + " for node id " + parentId; + LogHelper.Error(msg, attempt.Error); + throw new ApplicationException(msg); + } + return attempt.Result; + } + } + + private ApplicationTree GetTree(FormDataCollection queryStrings) + { + //need to ensure we have a tree type + var treeType = queryStrings.GetRequiredString("treeType"); + //now we'll look up that tree + var tree = Services.ApplicationTreeService.GetByAlias(treeType); + if (tree == null) + throw new InvalidOperationException("No tree found with alias " + treeType); + return tree; + } + + } } \ No newline at end of file diff --git a/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs b/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs index b746d45475..8e9c5d1704 100644 --- a/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs +++ b/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs @@ -81,7 +81,7 @@ namespace Umbraco.Web.Trees { if (length >= s) { - collection.ElementAt(s).Seperator = true; + collection.ElementAt(s).SeperatorBefore = true; } } @@ -252,7 +252,7 @@ namespace Umbraco.Web.Trees // /umbraco/tree.aspx?rnd=d0d0ff11a1c347dabfaa0fc75effcc2a&id=1046&treeType=content&contextMenu=false&isDialog=false //we need to convert the node source to our legacy tree controller - var childNodesSource = urlHelper.GetUmbracoApiService("GetNodes"); + var childNodesSource = urlHelper.GetUmbracoApiService("GetNodes"); var childQuery = (xmlTreeNode.Source.IsNullOrWhiteSpace() || xmlTreeNode.Source.IndexOf('?') == -1) ? "" @@ -263,7 +263,7 @@ namespace Umbraco.Web.Trees //for the menu source we need to detect if this is a root node since we'll need to set the parentId and id to -1 // for which we'll handle correctly on the server side. - var menuSource = urlHelper.GetUmbracoApiService("GetMenu"); + var menuSource = urlHelper.GetUmbracoApiService("GetMenu"); menuSource = menuSource.AppendQueryStringToUrl(new[] { "id=" + (isRoot ? "-1" : xmlTreeNode.NodeID), @@ -289,7 +289,7 @@ namespace Umbraco.Web.Trees var knownNonLegacyNodeTypes = new[] { "content", "contentRecycleBin", "mediaRecyleBin", "media" }; if (knownNonLegacyNodeTypes.InvariantContains(xmlTreeNode.NodeType) == false) { - node.OnClickCallback = xmlTreeNode.Action; + node.AssignLegacyJsCallback(xmlTreeNode.Action); } return node; } diff --git a/src/Umbraco.Web/Trees/MenuItem.cs b/src/Umbraco.Web/Trees/MenuItem.cs index 072d69f352..1e0ce12240 100644 --- a/src/Umbraco.Web/Trees/MenuItem.cs +++ b/src/Umbraco.Web/Trees/MenuItem.cs @@ -18,10 +18,13 @@ namespace Umbraco.Web.Trees { Name = legacyMenu.Alias; Alias = legacyMenu.Alias; - Seperator = false; + SeperatorBefore = false; Icon = legacyMenu.Icon; + Action = legacyMenu; } + internal IAction Action { get; private set; } + /// /// A dictionary to support any additional meta data that should be rendered for the node which is /// useful for custom action commands such as 'create', 'copy', etc... @@ -41,8 +44,11 @@ namespace Umbraco.Web.Trees [Required] public string Alias { get; set; } + /// + /// Ensures a menu separator will exist before this menu item + /// [DataMember(Name = "seperator")] - public bool Seperator { get; set; } + public bool SeperatorBefore { get; set; } [DataMember(Name = "cssclass")] public string Icon { get; set; } diff --git a/src/Umbraco.Web/Trees/MenuItemCollection.cs b/src/Umbraco.Web/Trees/MenuItemCollection.cs index 1dbb18e4ba..c0e0e5429a 100644 --- a/src/Umbraco.Web/Trees/MenuItemCollection.cs +++ b/src/Umbraco.Web/Trees/MenuItemCollection.cs @@ -14,6 +14,11 @@ namespace Umbraco.Web.Trees } + public MenuItemCollection(IEnumerable items) + { + _menuItems = new List(items); + } + private readonly List _menuItems = new List(); /// @@ -40,10 +45,18 @@ namespace Umbraco.Web.Trees /// Adds a menu item /// /// - public void AddMenuItem() + public MenuItem AddMenuItem() where T : IAction { - AddMenuItem(null); + return AddMenuItem(null); + } + + public MenuItem AddMenuItem(bool hasSeparator) + where T : IAction + { + var item = AddMenuItem(); + item.SeperatorBefore = hasSeparator; + return item; } /// @@ -52,10 +65,10 @@ namespace Umbraco.Web.Trees /// /// /// - public void AddMenuItem(string key, string value) + public MenuItem AddMenuItem(string key, string value) where T : IAction { - AddMenuItem(new Dictionary { { key, value } }); + return AddMenuItem(new Dictionary { { key, value } }); } /// @@ -63,7 +76,7 @@ namespace Umbraco.Web.Trees /// /// /// - public void AddMenuItem(IDictionary additionalData) + public MenuItem AddMenuItem(IDictionary additionalData) where T : IAction { var item = ActionsResolver.Current.GetAction(); @@ -86,7 +99,10 @@ namespace Umbraco.Web.Trees ////validate the data in the meta data bag //item.ValidateRequiredData(AdditionalData); + + return menuItem; } + return null; } public IEnumerator GetEnumerator() diff --git a/src/Umbraco.Web/Trees/TestTreeApiController.cs b/src/Umbraco.Web/Trees/TestTreeApiController.cs deleted file mode 100644 index 50db9750ed..0000000000 --- a/src/Umbraco.Web/Trees/TestTreeApiController.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Globalization; -using System.Net.Http.Formatting; -using umbraco.businesslogic; - -namespace Umbraco.Web.Trees -{ - //[Tree("test", "test", "Test Tree")] - //public class TestTreeApiController : TreeApiController - //{ - // protected override TreeNodeCollection GetTreeData(string id, FormDataCollection queryStrings) - // { - // var collection = new TreeNodeCollection - // { - // CreateTreeNode("1", queryStrings, "Node 1", ""), - // CreateTreeNode("2", queryStrings, "Node 2", ""), - // CreateTreeNode("3", queryStrings, "Node 3", ""), - // CreateTreeNode("4", queryStrings, "Node 4", ""), - // }; - // collection[0].AdditionalData.Add("TestKey", "TestVal"); - // return collection; - // } - - // //protected override string RootNodeId - // //{ - // // get { return (-1).ToString(CultureInfo.InvariantCulture); } - // //} - //} -} \ No newline at end of file diff --git a/src/Umbraco.Web/Trees/TreeApiController.cs b/src/Umbraco.Web/Trees/TreeApiController.cs index c6e9e59585..e495b6ae08 100644 --- a/src/Umbraco.Web/Trees/TreeApiController.cs +++ b/src/Umbraco.Web/Trees/TreeApiController.cs @@ -5,17 +5,16 @@ using System.Net.Http.Formatting; using Umbraco.Core; using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Filters; -using umbraco.businesslogic; namespace Umbraco.Web.Trees { - //NOTE: We will of course have to authorized this but changing the base class once integrated - /// /// The base controller for all tree requests - /// + /// public abstract class TreeApiController : UmbracoAuthorizedApiController { + private readonly TreeAttribute _attribute; + /// /// Remove the xml formatter... only support JSON! /// @@ -40,10 +39,7 @@ namespace Umbraco.Web.Trees } //assign the properties of this object to those of the metadata attribute - var attr = treeAttributes.First(); - //TreeId = attr.Id; - RootNodeDisplayName = attr.Title; - NodeCollection = new TreeNodeCollection(); + _attribute = treeAttributes.First(); } /// @@ -66,17 +62,27 @@ namespace Umbraco.Web.Trees /// /// protected abstract MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings); - - ///// - ///// Returns the root node for the tree - ///// - //protected abstract string RootNodeId { get; } /// /// The name to display on the root node /// - public string RootNodeDisplayName { get; private set; } - + public virtual string RootNodeDisplayName + { + get { return _attribute.Title; } + } + + /// + /// Returns the root node for the tree + /// + /// + /// + [HttpQueryStringFilter("queryStrings")] + public TreeNode GetRootNode(FormDataCollection queryStrings) + { + if (queryStrings == null) queryStrings = new FormDataCollection(""); + return CreateRootNode(queryStrings); + } + /// /// The action called to render the contents of the tree structure /// @@ -93,10 +99,7 @@ namespace Umbraco.Web.Trees public TreeNodeCollection GetNodes(string id, FormDataCollection queryStrings) { if (queryStrings == null) queryStrings = new FormDataCollection(""); - //if its the root node, render it otherwise render normal nodes - return AddRootNodeToCollection(id, queryStrings) - ? NodeCollection - : GetTreeData(id, queryStrings); + return GetTreeData(id, queryStrings); } /// @@ -109,7 +112,6 @@ namespace Umbraco.Web.Trees public MenuItemCollection GetMenu(string id, FormDataCollection queryStrings) { if (queryStrings == null) queryStrings = new FormDataCollection(""); - return GetMenuForNode(id, queryStrings); } @@ -126,7 +128,7 @@ namespace Umbraco.Web.Trees rootNodeAsString, queryStrings); - var getMenuUrl = Url.GetTreeUrl( + var getMenuUrl = Url.GetMenuUrl( GetType(), rootNodeAsString, queryStrings); @@ -186,156 +188,90 @@ namespace Umbraco.Web.Trees node.AdditionalData.Add(q.Key, q.Value); } } + + #region Create TreeNode methods /// - /// Checks if the node Id is the root node and if so creates the root node and appends it to the - /// NodeCollection based on the standard tree parameters + /// Helper method to create tree nodes /// /// /// + /// /// - /// - /// This method ensure that all of the correct meta data is set for the root node so that the Umbraco application works - /// as expected. Meta data such as 'treeId' and 'searchable' - /// - protected bool AddRootNodeToCollection(string id, FormDataCollection queryStrings) - { - //if its the root model - if (id == Constants.System.Root.ToString(CultureInfo.InvariantCulture)) - { - //get the root model - var rootNode = CreateRootNode(queryStrings); - - NodeCollection.Add(rootNode); - - return true; - } - - return false; + public TreeNode CreateTreeNode(string id, FormDataCollection queryStrings, string title) + { + var jsonUrl = Url.GetTreeUrl(GetType(), id, queryStrings); + var menuUrl = Url.GetMenuUrl(GetType(), id, queryStrings); + var node = new TreeNode(id, jsonUrl, menuUrl) { Title = title }; + return node; } - #region Create TreeNode methods + /// + /// Helper method to create tree nodes + /// + /// + /// + /// + /// + /// + public TreeNode CreateTreeNode(string id, FormDataCollection queryStrings, string title, string icon) + { + var jsonUrl = Url.GetTreeUrl(GetType(), id, queryStrings); + var menuUrl = Url.GetMenuUrl(GetType(), id, queryStrings); + var node = new TreeNode(id, jsonUrl, menuUrl) { Title = title, Icon = icon }; + return node; + } + + /// + /// Helper method to create tree nodes + /// + /// + /// + /// + /// + /// + /// + public TreeNode CreateTreeNode(string id, FormDataCollection queryStrings, string title, string icon, string routePath) + { + var jsonUrl = Url.GetTreeUrl(GetType(), id, queryStrings); + var menuUrl = Url.GetMenuUrl(GetType(), id, queryStrings); + var node = new TreeNode(id, jsonUrl, menuUrl) { Title = title, RoutePath = routePath, Icon = icon }; + return node; + } - ///// - ///// Helper method to create tree nodes and automatically generate the json url - ///// - ///// - ///// - ///// - ///// - ///// - //public TreeNode CreateTreeNode(string id, FormDataCollection queryStrings, string title, string editorUrl) - //{ - // var jsonUrl = Url.GetTreeUrl(GetType(), id, queryStrings); - // //var node = new TreeNode(id, BackOfficeRequestContext.RegisteredComponents.MenuItems, jsonUrl) { Title = title, EditorUrl = editorUrl }; - // var node = new TreeNode(id, jsonUrl) { Title = title, EditorUrl = editorUrl }; - // return node; - //} + /// + /// Helper method to create tree nodes and automatically generate the json url + /// + /// + /// + /// + /// + /// + /// + public TreeNode CreateTreeNode(string id, FormDataCollection queryStrings, string title, string icon, bool hasChildren) + { + var treeNode = CreateTreeNode(id, queryStrings, title, icon); + treeNode.HasChildren = hasChildren; + return treeNode; + } - ///// - ///// Helper method to create tree nodes and automatically generate the json url - ///// - ///// - ///// - ///// - ///// - ///// - ///// - //public TreeNode CreateTreeNode(string id, FormDataCollection queryStrings, string title, string editorUrl, string action) - //{ - // var jsonUrl = Url.GetTreeUrl(GetType(), id, queryStrings); - // //var node = new TreeNode(id, BackOfficeRequestContext.RegisteredComponents.MenuItems, jsonUrl) { Title = title, EditorUrl = editorUrl }; - // var node = new TreeNode(id, jsonUrl) { Title = title, EditorUrl = editorUrl }; - // return node; - //} - - ///// - ///// Helper method to create tree nodes and automatically generate the json url - ///// - ///// - ///// - ///// - ///// - ///// - ///// - ///// - //public TreeNode CreateTreeNode(string id, FormDataCollection queryStrings, string title, string editorUrl, string action, string icon) - //{ - // var jsonUrl = Url.GetTreeUrl(GetType(), id, queryStrings); - // //var node = new TreeNode(id, BackOfficeRequestContext.RegisteredComponents.MenuItems, jsonUrl) { Title = title, EditorUrl = editorUrl }; - // var node = new TreeNode(id, jsonUrl) { Title = title, EditorUrl = editorUrl }; - // return node; - //} - - ///// - ///// Helper method to create tree nodes and automatically generate the json url - ///// - ///// - ///// - ///// - ///// - ///// - ///// - ///// - //public TreeNode CreateTreeNode(string id, FormDataCollection queryStrings, string title, string editorUrl, string action, bool hasChildren) - //{ - // var treeNode = CreateTreeNode(id, queryStrings, title, editorUrl, action); - // treeNode.HasChildren = hasChildren; - // return treeNode; - //} - - ///// - ///// Helper method to create tree nodes and automatically generate the json url - ///// - ///// - ///// - ///// - ///// - ///// - ///// - ///// - ///// - //public TreeNode CreateTreeNode(string id, FormDataCollection queryStrings, string title, string editorUrl, string action, bool hasChildren, string icon) - //{ - // var treeNode = CreateTreeNode(id, queryStrings, title, editorUrl, action); - // treeNode.HasChildren = hasChildren; - // treeNode.Icon = icon; - // return treeNode; - //} - - ///// - ///// Helper method to create tree nodes and automatically generate the json url - ///// - ///// - ///// - ///// - ///// - ///// - ///// - //public TreeNode CreateTreeNode(string id, FormDataCollection queryStrings, string title, string editorUrl, bool hasChildren) - //{ - // var treeNode = CreateTreeNode(id, queryStrings, title, editorUrl); - // treeNode.HasChildren = hasChildren; - // return treeNode; - //} - - ///// - ///// Helper method to create tree nodes and automatically generate the json url - ///// - ///// - ///// - ///// - ///// - ///// - ///// - ///// - //public TreeNode CreateTreeNode(string id, FormDataCollection queryStrings, string title, string editorUrl, bool hasChildren, string icon) - //{ - // var treeNode = CreateTreeNode(id, queryStrings, title, editorUrl); - // treeNode.HasChildren = hasChildren; - // treeNode.Icon = icon; - // return treeNode; - //} + /// + /// Helper method to create tree nodes and automatically generate the json url + /// + /// + /// + /// + /// + /// + /// + /// + public TreeNode CreateTreeNode(string id, FormDataCollection queryStrings, string title, string icon, bool hasChildren, string routePath) + { + var treeNode = CreateTreeNode(id, queryStrings, title, icon); + treeNode.HasChildren = hasChildren; + treeNode.RoutePath = routePath; + return treeNode; + } #endregion @@ -350,11 +286,7 @@ namespace Umbraco.Web.Trees return name.Substring(0, name.LastIndexOf("TreeController", StringComparison.Ordinal)); } } - - /// - /// The model collection for trees to add nodes to - /// - protected TreeNodeCollection NodeCollection { get; private set; } + } } diff --git a/src/Umbraco.Web/Trees/TreeAttribute.cs b/src/Umbraco.Web/Trees/TreeAttribute.cs new file mode 100644 index 0000000000..16c03cba82 --- /dev/null +++ b/src/Umbraco.Web/Trees/TreeAttribute.cs @@ -0,0 +1,46 @@ +using System; + +namespace Umbraco.Web.Trees +{ + /// + /// Identifies an application tree + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] + public class TreeAttribute : Attribute + { + /// + /// Initializes a new instance of the class. + /// + /// The app alias. + /// The alias. + /// The title. + /// The icon closed. + /// The icon open. + /// if set to true [initialize]. + /// The sort order. + public TreeAttribute(string appAlias, + string alias, + string title, + string iconClosed = "icon-folder", + string iconOpen = "icon-folder-open", + bool initialize = true, + int sortOrder = 0) + { + ApplicationAlias = appAlias; + Alias = alias; + Title = title; + IconClosed = iconClosed; + IconOpen = iconOpen; + Initialize = initialize; + SortOrder = sortOrder; + } + + public string ApplicationAlias { get; private set; } + public string Alias { get; private set; } + public string Title { get; private set; } + public string IconClosed { get; private set; } + public string IconOpen { get; private set; } + public bool Initialize { get; private set; } + public int SortOrder { get; private set; } + } +} diff --git a/src/Umbraco.Web/Trees/TreeNode.cs b/src/Umbraco.Web/Trees/TreeNode.cs index aee383e97d..0694fdb4fb 100644 --- a/src/Umbraco.Web/Trees/TreeNode.cs +++ b/src/Umbraco.Web/Trees/TreeNode.cs @@ -13,7 +13,13 @@ namespace Umbraco.Web.Trees public class TreeNode { - public TreeNode(string nodeId, string getChildNodesUrl, string menuUrl) + /// + /// Internal constructor, to create a tree node use the CreateTreeNode methods of the TreeApiController. + /// + /// + /// + /// + internal TreeNode(string nodeId, string getChildNodesUrl, string menuUrl) { //_menuItems = menuItems; //Style = new NodeStyle(); @@ -21,6 +27,8 @@ namespace Umbraco.Web.Trees AdditionalData = new Dictionary(); ChildNodesUrl = getChildNodesUrl; MenuUrl = menuUrl; + //default + Icon = "icon-folder-close"; } /// @@ -44,8 +52,8 @@ namespace Umbraco.Web.Trees /// /// Gets or sets the node path. /// - [DataMember(Name = "path")] - public string Path { get; set; } + [DataMember(Name = "nodePath")] + public string NodePath { get; set; } /// /// The icon to use for the node, this can be either a path to an image or a Css class. @@ -92,27 +100,15 @@ namespace Umbraco.Web.Trees } } - ///// - ///// The URL path for the editor for this model - ///// - ///// - ///// If this is set then the UI will attempt to load the result of this URL into an IFrame - ///// for the editor. - ///// - ///// Generally for use with Legacy trees - ///// - //[DataMember(Name = "editorUrl")] - //internal string EditorUrl { get; set; } - /// - /// A JS method/codeblock to be called when the tree node is clicked + /// Optional: The Route path for the editor for this node /// /// - /// This should only be used for legacy trees + /// If this is not set, then the route path will be automatically determined by: {section}/edit/{id} /// - [DataMember(Name = "jsClickCallback")] - internal string OnClickCallback { get; set; } - + [DataMember(Name = "routePath")] + public string RoutePath { get; set; } + /// /// The JSON url to load the nodes children /// diff --git a/src/Umbraco.Web/Trees/TreeNodeExtensions.cs b/src/Umbraco.Web/Trees/TreeNodeExtensions.cs new file mode 100644 index 0000000000..f26f0d4328 --- /dev/null +++ b/src/Umbraco.Web/Trees/TreeNodeExtensions.cs @@ -0,0 +1,17 @@ +namespace Umbraco.Web.Trees +{ + public static class TreeNodeExtensions + { + internal const string LegacyJsCallbackKey = "jsClickCallback"; + + /// + /// Legacy tree node's assign a JS method callback for when an item is clicked, this method facilitates that. + /// + /// + /// + internal static void AssignLegacyJsCallback(this TreeNode treeNode, string jsCallback) + { + treeNode.AdditionalData[LegacyJsCallbackKey] = jsCallback; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 927a6490de..08644b2413 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -343,7 +343,8 @@ - + + @@ -355,14 +356,16 @@ + + - + diff --git a/src/umbraco.businesslogic/ApplicationTreeRegistrar.cs b/src/umbraco.businesslogic/ApplicationTreeRegistrar.cs index ace259bd57..d7cee66c82 100644 --- a/src/umbraco.businesslogic/ApplicationTreeRegistrar.cs +++ b/src/umbraco.businesslogic/ApplicationTreeRegistrar.cs @@ -12,21 +12,12 @@ using umbraco.interfaces; namespace umbraco.BusinessLogic { - - //TODO: We should move this to Core but currently the legacy tree attribute exists here, perhaps we need two startup handlers - // one to register the legacy ones and one to register the new ones?? And create a new attribute - /// /// A startup handler for dealing with trees /// + [Obsolete("This is no longer used, currenltly only here to register some model mappers")] public class ApplicationTreeRegistrar : ApplicationEventHandler, IMapperConfiguration - { - - protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext) - { - ScanTrees(applicationContext); - } - + { /// /// Configures automapper model mappings /// @@ -36,44 +27,6 @@ namespace umbraco.BusinessLogic .ReverseMap(); //two way } - /// - /// Scans for all attributed trees and ensures they exist in the tree xml - /// - private static void ScanTrees(ApplicationContext applicationContext) - { - // Load all Trees by attribute and add them to the XML config - var types = PluginManager.Current.ResolveAttributedTrees(); - - var items = types - .Select(x => - new Tuple(x, x.GetCustomAttributes(false).Single())) - .Where(x => applicationContext.Services.ApplicationTreeService.GetByAlias(x.Item2.Alias) == null); - - applicationContext.Services.ApplicationTreeService.LoadXml(doc => - { - foreach (var tuple in items) - { - var type = tuple.Item1; - var attr = tuple.Item2; - - //Add the new tree that doesn't exist in the config that was found by type finding - - doc.Root.Add(new XElement("add", - new XAttribute("silent", attr.Silent), - new XAttribute("initialize", attr.Initialize), - new XAttribute("sortOrder", attr.SortOrder), - new XAttribute("alias", attr.Alias), - new XAttribute("application", attr.ApplicationAlias), - new XAttribute("title", attr.Title), - new XAttribute("iconClosed", attr.IconClosed), - new XAttribute("iconOpen", attr.IconOpen), - new XAttribute("type", type.GetFullNameWithAssembly()), - new XAttribute("action", attr.Action))); - } - - }, true); - } - } } \ No newline at end of file diff --git a/src/umbraco.businesslogic/TreeAttribute.cs b/src/umbraco.businesslogic/TreeAttribute.cs index 631fbcafe2..f5089ca276 100644 --- a/src/umbraco.businesslogic/TreeAttribute.cs +++ b/src/umbraco.businesslogic/TreeAttribute.cs @@ -49,8 +49,13 @@ namespace umbraco.businesslogic public string Title { get; private set; } public string IconClosed { get; private set; } public string IconOpen { get; private set; } + + [Obsolete("This doesn't do anything")] public string Action { get; private set; } + + [Obsolete("This doesn't do anything")] public bool Silent { get; private set; } + public bool Initialize { get; private set; } public int SortOrder { get; private set; } }