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 0ce43585d3..6c03c4ed11 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
@@ -40,13 +40,22 @@ function treeService($q, treeResource, iconHelper, notificationsService, $rootSc
_formatNodeDataForUseInUI: function (parentNode, treeNodes, section, level) {
//if no level is set, then we make it 1
var childLevel = (level ? level : 1);
+ //set the section if it's not already set
if (!parentNode.section) {
parentNode.section = section;
}
+ //create a method outside of the loop to return the parent - otherwise jshint blows up
+ var funcParent = function() {
+ return parentNode;
+ };
for (var i = 0; i < treeNodes.length; i++) {
treeNodes[i].level = childLevel;
- treeNodes[i].parent = parentNode;
+
+ //create a function to get the parent node, we could assign the parent node but
+ // then we cannot serialize this entity because we have a cyclical reference.
+ // Instead we just make a function to return the parentNode.
+ treeNodes[i].parent = funcParent;
//set the section for each tree node - this allows us to reference this easily when accessing tree nodes
treeNodes[i].section = section;
@@ -242,11 +251,11 @@ function treeService($q, treeResource, iconHelper, notificationsService, $rootSc
/** Removes a given tree node from the tree */
removeNode: function(treeNode) {
- if (treeNode.parent == null) {
+ if (treeNode.parent() == null) {
throw "Cannot remove a node that doesn't have a parent";
}
//remove the current item from it's siblings
- treeNode.parent.children.splice(treeNode.parent.children.indexOf(treeNode), 1);
+ treeNode.parent().children.splice(treeNode.parent().children.indexOf(treeNode), 1);
},
/** Removes all child nodes from a given tree node */
@@ -309,7 +318,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, $rootSc
root = current;
}
else {
- current = current.parent;
+ current = current.parent();
}
}
return root;
@@ -418,7 +427,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, $rootSc
if (!node) {
throw "node cannot be null";
}
- if (!node.parent) {
+ if (!node.parent()) {
throw "cannot reload a single node without a parent";
}
if (!node.section) {
@@ -430,7 +439,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, $rootSc
//set the node to loading
node.loading = true;
- this.getChildren({ node: node.parent, section: node.section }).then(function(data) {
+ this.getChildren({ node: node.parent(), section: node.section }).then(function(data) {
//ok, now that we have the children, find the node we're reloading
var found = _.find(data, function(item) {
@@ -438,14 +447,14 @@ function treeService($q, treeResource, iconHelper, notificationsService, $rootSc
});
if (found) {
//now we need to find the node in the parent.children collection to replace
- var index = _.indexOf(node.parent.children, node);
+ var index = _.indexOf(node.parent().children, node);
//the trick here is to not actually replace the node - this would cause the delete animations
//to fire, instead we're just going to replace all the properties of this node.
- _.extend(node.parent.children[index], found);
+ _.extend(node.parent().children[index], found);
//set the node to loading
- node.parent.children[index].loading = false;
+ node.parent().children[index].loading = false;
//return
- deferred.resolve(node.parent.children[index]);
+ deferred.resolve(node.parent().children[index]);
}
else {
deferred.reject();
diff --git a/src/Umbraco.Web.UI.Client/src/views/content/content.move.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/content.move.controller.js
index 7a44e6d580..cedb409117 100644
--- a/src/Umbraco.Web.UI.Client/src/views/content/content.move.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/content/content.move.controller.js
@@ -39,7 +39,7 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.MoveController",
$scope.success = true;
//reloads the parent
- navigationService.reloadNode(dialogOptions.currentNode.parent);
+ navigationService.reloadNode(dialogOptions.currentNode.parent());
//reloads the target
navigationService.syncTree({ tree: "content", path: path, forceReload: true });
diff --git a/src/Umbraco.Web.UI.Client/test/unit/common/services/tree-service.spec.js b/src/Umbraco.Web.UI.Client/test/unit/common/services/tree-service.spec.js
index 8659eadf07..c4d5ca49a5 100644
--- a/src/Umbraco.Web.UI.Client/test/unit/common/services/tree-service.spec.js
+++ b/src/Umbraco.Web.UI.Client/test/unit/common/services/tree-service.spec.js
@@ -253,7 +253,7 @@ describe('tree service tests', function () {
cacheKey: "__content",
filter: function (currentCache) {
var toRemove = treeService.getDescendantNode(currentCache.root, 1235);
- toRemove.parent.children = _.without(toRemove.parent.children, toRemove);
+ toRemove.parent().children = _.without(toRemove.parent().children, toRemove);
return currentCache;
}
});
@@ -286,8 +286,6 @@ describe('tree service tests', function () {
cache = treeService._getTreeCache();
- console.log(" blah: " + cache.__content.root.children.length);
-
expect(cache.__content.root.children.length).toBe(4);
expect(cache.__content.root.children[0].children).toBeNull();
expect(cache.__content.root.children[0].expanded).toBe(false);
diff --git a/src/Umbraco.Web/Models/Trees/SectionRootNode.cs b/src/Umbraco.Web/Models/Trees/SectionRootNode.cs
index 59b50a7792..3116159f5f 100644
--- a/src/Umbraco.Web/Models/Trees/SectionRootNode.cs
+++ b/src/Umbraco.Web/Models/Trees/SectionRootNode.cs
@@ -1,4 +1,5 @@
using System.Runtime.Serialization;
+using Umbraco.Core;
namespace Umbraco.Web.Models.Trees
{
@@ -33,7 +34,7 @@ namespace Umbraco.Web.Models.Trees
}
private SectionRootNode(string nodeId, string getChildNodesUrl, string menuUrl)
- : base(nodeId, getChildNodesUrl, menuUrl)
+ : base(nodeId, null, getChildNodesUrl, menuUrl)
{
//default to false
IsContainer = false;
diff --git a/src/Umbraco.Web/Models/Trees/TreeNode.cs b/src/Umbraco.Web/Models/Trees/TreeNode.cs
index c13fae94d9..c413edea37 100644
--- a/src/Umbraco.Web/Models/Trees/TreeNode.cs
+++ b/src/Umbraco.Web/Models/Trees/TreeNode.cs
@@ -19,11 +19,15 @@ namespace Umbraco.Web.Models.Trees
/// Internal constructor, to create a tree node use the CreateTreeNode methods of the TreeApiController.
///
///
+ /// The parent id for the current node
///
///
- internal TreeNode(string nodeId, string getChildNodesUrl, string menuUrl)
+ internal TreeNode(string nodeId, string parentId, string getChildNodesUrl, string menuUrl)
{
+ Mandate.ParameterNotNullOrEmpty(nodeId, "nodeId");
+
Id = nodeId;
+ ParentId = parentId;
ChildNodesUrl = getChildNodesUrl;
MenuUrl = menuUrl;
CssClasses = new List();
@@ -31,6 +35,9 @@ namespace Umbraco.Web.Models.Trees
Icon = "icon-folder-close";
}
+ [DataMember(Name = "parentId", IsRequired = true)]
+ public new object ParentId { get; set; }
+
///
/// A flag to set whether or not this node has children
///
@@ -63,13 +70,6 @@ namespace Umbraco.Web.Models.Trees
///
[DataMember(Name = "menuUrl")]
public string MenuUrl { get; set; }
-
- ///
- /// The icon to use for the node, this can be either a path to an image or a Css class.
- /// If a '/' is found in the string then it will be considered a path to an image.
- ///
- [DataMember(Name = "icon")]
- public string Icon { get; set; }
///
/// Returns true if the icon represents a CSS class instead of a file path
diff --git a/src/Umbraco.Web/Trees/ContentTreeController.cs b/src/Umbraco.Web/Trees/ContentTreeController.cs
index 5bfa20e030..9cfc2bcb14 100644
--- a/src/Umbraco.Web/Trees/ContentTreeController.cs
+++ b/src/Umbraco.Web/Trees/ContentTreeController.cs
@@ -75,6 +75,7 @@ namespace Umbraco.Web.Trees
var node = CreateTreeNode(
e.Id.ToInvariantString(),
+ id,
queryStrings,
e.Name,
e.ContentTypeIcon,
diff --git a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs
index 352f0c3521..5b9a6181f3 100644
--- a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs
+++ b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs
@@ -72,6 +72,7 @@ namespace Umbraco.Web.Trees
{
nodes.Add(CreateTreeNode(
RecycleBinId.ToInvariantString(),
+ id,
queryStrings,
ui.GetText("general", "recycleBin"),
"icon-trash",
diff --git a/src/Umbraco.Web/Trees/DataTypeTreeController.cs b/src/Umbraco.Web/Trees/DataTypeTreeController.cs
index 76d934c9cf..c41deb350b 100644
--- a/src/Umbraco.Web/Trees/DataTypeTreeController.cs
+++ b/src/Umbraco.Web/Trees/DataTypeTreeController.cs
@@ -33,6 +33,7 @@ namespace Umbraco.Web.Trees
.Select(dt =>
CreateTreeNode(
dt.Id.ToInvariantString(),
+ id,
queryStrings,
dt.Name,
"icon-autofill",
diff --git a/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs b/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs
index 5aacb96f40..9cce00779f 100644
--- a/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs
+++ b/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs
@@ -348,7 +348,7 @@ namespace Umbraco.Web.Trees
//TODO: Might need to add stuff to additional attributes
- var node = new TreeNode(xmlTreeNode.NodeID, childNodesSource, menuSource)
+ var node = new TreeNode(xmlTreeNode.NodeID, isRoot ? null : parentId, childNodesSource, menuSource)
{
HasChildren = xmlTreeNode.HasChildren,
Icon = xmlTreeNode.Icon,
diff --git a/src/Umbraco.Web/Trees/MediaTreeController.cs b/src/Umbraco.Web/Trees/MediaTreeController.cs
index fd85910c8f..e8283b0f90 100644
--- a/src/Umbraco.Web/Trees/MediaTreeController.cs
+++ b/src/Umbraco.Web/Trees/MediaTreeController.cs
@@ -55,7 +55,7 @@ namespace Umbraco.Web.Trees
foreach (var entity in entities)
{
var e = (UmbracoEntity)entity;
- var node = CreateTreeNode(e.Id.ToInvariantString(), queryStrings, e.Name, e.ContentTypeIcon, e.HasChildren);
+ var node = CreateTreeNode(e.Id.ToInvariantString(), id, queryStrings, e.Name, e.ContentTypeIcon, e.HasChildren);
node.AdditionalData.Add("contentType", e.ContentTypeAlias);
nodes.Add(node);
diff --git a/src/Umbraco.Web/Trees/MemberTreeController.cs b/src/Umbraco.Web/Trees/MemberTreeController.cs
index f7d536c083..6d4c2eb743 100644
--- a/src/Umbraco.Web/Trees/MemberTreeController.cs
+++ b/src/Umbraco.Web/Trees/MemberTreeController.cs
@@ -30,14 +30,14 @@ namespace Umbraco.Web.Trees
for (var i = 97; i < 123; i++)
{
var charString = ((char) i).ToString(CultureInfo.InvariantCulture);
- var folder = CreateTreeNode(charString, queryStrings, charString, "icon-folder-close", true);
+ var folder = CreateTreeNode(charString, id, queryStrings, charString, "icon-folder-close", true);
folder.NodeType = "member-folder";
nodes.Add(folder);
}
//list out 'Others' if the membership provider is umbraco
if (Member.InUmbracoMemberMode())
{
- var folder = CreateTreeNode("others", queryStrings, "Others", "icon-folder-close", true);
+ var folder = CreateTreeNode("others", id, queryStrings, "Others", "icon-folder-close", true);
folder.NodeType = "member-folder";
nodes.Add(folder);
}
@@ -52,7 +52,7 @@ namespace Umbraco.Web.Trees
//get the members from our member data layer
nodes.AddRange(
Member.getMemberFromFirstLetter(id.ToCharArray()[0])
- .Select(m => CreateTreeNode(m.UniqueId.ToString("N"), queryStrings, m.Text, "icon-user")));
+ .Select(m => CreateTreeNode(m.UniqueId.ToString("N"), id, queryStrings, m.Text, "icon-user")));
}
else
{
@@ -60,7 +60,7 @@ namespace Umbraco.Web.Trees
int total;
nodes.AddRange(
Membership.Provider.FindUsersByName(id + "%", 0, 9999, out total).Cast()
- .Select(m => CreateTreeNode(m.ProviderUserKey.ToString(), queryStrings, m.UserName, "icon-user")));
+ .Select(m => CreateTreeNode(m.ProviderUserKey.ToString(), id, queryStrings, m.UserName, "icon-user")));
}
}
else if (id == "others")
@@ -68,7 +68,7 @@ namespace Umbraco.Web.Trees
//others will only show up when in umbraco membership mode
nodes.AddRange(
Member.getAllOtherMembers()
- .Select(m => CreateTreeNode(m.Id.ToInvariantString(), queryStrings, m.Text, "icon-user")));
+ .Select(m => CreateTreeNode(m.Id.ToInvariantString(), id, queryStrings, m.Text, "icon-user")));
}
}
return nodes;
diff --git a/src/Umbraco.Web/Trees/TreeControllerBase.cs b/src/Umbraco.Web/Trees/TreeControllerBase.cs
index 35c8d75de5..e31cb85b0d 100644
--- a/src/Umbraco.Web/Trees/TreeControllerBase.cs
+++ b/src/Umbraco.Web/Trees/TreeControllerBase.cs
@@ -155,6 +155,7 @@ namespace Umbraco.Web.Trees
var node = new TreeNode(
rootNodeAsString,
+ null, //this is a root node, there is no parent
Url.GetTreeUrl(GetType(), rootNodeAsString, queryStrings),
Url.GetMenuUrl(GetType(), rootNodeAsString, queryStrings))
{
@@ -172,14 +173,15 @@ namespace Umbraco.Web.Trees
/// Helper method to create tree nodes
///
///
+ ///
///
///
///
- public TreeNode CreateTreeNode(string id, FormDataCollection queryStrings, string title)
+ public TreeNode CreateTreeNode(string id, string parentId, 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) { Name = title };
+ var node = new TreeNode(id, parentId, jsonUrl, menuUrl) { Name = title };
return node;
}
@@ -187,15 +189,16 @@ namespace Umbraco.Web.Trees
/// Helper method to create tree nodes
///
///
+ ///
///
///
///
///
- public TreeNode CreateTreeNode(string id, FormDataCollection queryStrings, string title, string icon)
+ public TreeNode CreateTreeNode(string id, string parentId, 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) { Name = title, Icon = icon };
+ var node = new TreeNode(id, parentId, jsonUrl, menuUrl) { Name = title, Icon = icon };
return node;
}
@@ -203,16 +206,17 @@ namespace Umbraco.Web.Trees
/// Helper method to create tree nodes
///
///
+ ///
///
///
///
///
///
- public TreeNode CreateTreeNode(string id, FormDataCollection queryStrings, string title, string icon, string routePath)
+ public TreeNode CreateTreeNode(string id, string parentId, 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) { Name = title, RoutePath = routePath, Icon = icon };
+ var node = new TreeNode(id, parentId, jsonUrl, menuUrl) { Name = title, RoutePath = routePath, Icon = icon };
return node;
}
@@ -220,14 +224,15 @@ namespace Umbraco.Web.Trees
/// 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)
+ public TreeNode CreateTreeNode(string id, string parentId, FormDataCollection queryStrings, string title, string icon, bool hasChildren)
{
- var treeNode = CreateTreeNode(id, queryStrings, title, icon);
+ var treeNode = CreateTreeNode(id, parentId, queryStrings, title, icon);
treeNode.HasChildren = hasChildren;
return treeNode;
}
@@ -236,15 +241,16 @@ namespace Umbraco.Web.Trees
/// 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)
+ public TreeNode CreateTreeNode(string id, string parentId, FormDataCollection queryStrings, string title, string icon, bool hasChildren, string routePath)
{
- var treeNode = CreateTreeNode(id, queryStrings, title, icon);
+ var treeNode = CreateTreeNode(id, parentId, queryStrings, title, icon);
treeNode.HasChildren = hasChildren;
treeNode.RoutePath = routePath;
return treeNode;