diff --git a/src/Umbraco.Web.UI.Client/lib/umbraco/LegacyUmbClientMgr.js b/src/Umbraco.Web.UI.Client/lib/umbraco/LegacyUmbClientMgr.js index bfc7ddebac..8d382596f2 100644 --- a/src/Umbraco.Web.UI.Client/lib/umbraco/LegacyUmbClientMgr.js +++ b/src/Umbraco.Web.UI.Client/lib/umbraco/LegacyUmbClientMgr.js @@ -83,6 +83,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Application"); mainTree: function() { var injector = getRootInjector(); var navService = injector.get("navigationService"); + var appState = injector.get("appState"); var angularHelper = injector.get("angularHelper"); var $rootScope = injector.get("$rootScope"); @@ -116,9 +117,10 @@ Umbraco.Sys.registerNamespace("Umbraco.Application"); }, moveNode: function (id, path) { angularHelper.safeApply($rootScope, function() { - if (navService.ui.currentNode) { + var currentMenuNode = appState.getMenuState("currentNode"); + if (currentMenuNode) { var treeService = injector.get("treeService"); - var treeRoot = treeService.getTreeRoot(navService.ui.currentNode); + var treeRoot = treeService.getTreeRoot(currentMenuNode); if (treeRoot) { var found = treeService.getDescendantNode(treeRoot, id); if (found) { @@ -131,12 +133,17 @@ Umbraco.Sys.registerNamespace("Umbraco.Application"); }, getActionNode: function () { //need to replicate the legacy tree node + var currentMenuNode = appState.getMenuState("currentNode"); + if (!currentMenuNode) { + return null; + } + var legacyNode = { - nodeId: navService.ui.currentNode.id, - nodeName: navService.ui.currentNode.name, - nodeType: navService.ui.currentNode.nodeType, - treeType: navService.ui.currentNode.nodeType, - sourceUrl: navService.ui.currentNode.childNodesUrl, + nodeId: currentMenuNode.id, + nodeName: currentMenuNode.name, + nodeType: currentMenuNode.nodeType, + treeType: currentMenuNode.nodeType, + sourceUrl: currentMenuNode.childNodesUrl, updateDefinition: function() { throw "'updateDefinition' method is not supported in Umbraco 7, consider upgrading to the new v7 APIs"; } diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/umbtree.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/umbtree.directive.js index 2b3798481c..abf22e5979 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/umbtree.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/umbtree.directive.js @@ -133,11 +133,11 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat } //reset current node selection - scope.currentNode = undefined; + //scope.currentNode = null; //filter the path for root node ids args.path = _.filter(args.path, function (item) { return (item !== "init" && item !== "-1"); }); - loadPath(args.path, args.forceReload); + loadPath(args.path, args.forceReload, args.activate); return deferred.promise; }; @@ -157,18 +157,14 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat //helper to load a specific path on the active tree as soon as its ready - function loadPath(path, forceReload) { - - function _load(tree, path, forceReload) { - syncTree(tree, path, forceReload); - } + function loadPath(path, forceReload, activate) { if (scope.activeTree) { - _load(scope.activeTree, path, forceReload); + syncTree(scope.activeTree, path, forceReload, activate); } else { - scope.eventhandler.one("activeTreeLoaded", function(e, args) { - _load(args.tree, path, forceReload); + scope.eventhandler.one("activeTreeLoaded", function (e, args) { + syncTree(args.tree, path, forceReload, activate); }); } } @@ -181,8 +177,7 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat function loadActiveTree(treeAlias, loadChildren) { scope.activeTree = undefined; - function _load(tree) { - + function doLoad(tree) { var childrenAndSelf = [tree].concat(tree.children); scope.activeTree = _.find(childrenAndSelf, function (node) { return node.metaData.treeAlias === treeAlias; @@ -205,11 +200,11 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat } if (scope.tree) { - _load(scope.tree.root); + doLoad(scope.tree.root); } else { scope.eventhandler.one("treeLoaded", function(e, args) { - _load(args.tree); + doLoad(args.tree); }); } } @@ -245,7 +240,7 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat } /** syncs the tree, the treeNode can be ANY tree node in the tree that requires syncing */ - function syncTree(treeNode, path, forceReload) { + function syncTree(treeNode, path, forceReload, activate) { deleteAnimations = false; @@ -254,8 +249,12 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat path: path, forceReload: forceReload }).then(function (data) { - scope.currentNode = data; - emitEvent("treeSynced", { node: data }); + + if (activate === undefined || activate === true) { + scope.currentNode = data; + } + + emitEvent("treeSynced", { node: data, activate: activate }); enableDeleteAnimations(); }); @@ -326,7 +325,12 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat and emits it as a treeNodeSelect element if there is a callback object defined on the tree */ - scope.select = function(e, n, ev) { + scope.select = function (e, n, ev) { + //on tree select we need to remove the current node - + // whoever handles this will need to make sure the correct node is selected + //reset current node selection + scope.currentNode = null; + emitEvent("treeNodeSelect", { element: e, node: n, event: ev }); }; diff --git a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js index d488810180..dd979ebb6a 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js @@ -206,11 +206,12 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo //when a tree node is synced this event will fire, this allows us to set the currentNode mainTreeEventHandler.bind("treeSynced", function (ev, args) { - //set the global current node - ui.currentNode = args.node; - //not sure what this is doing - scope.currentNode = args.node; - //what the heck is going on here? - this seems really zany, allowing us to modify the + if (args.activate === undefined || args.activate === true) { + //set the current selected node + appState.setTreeState("selectedNode", args.node); + } + + //TODO: what the heck is going on here? - this seems really zany, allowing us to modify the // navigationController.scope from within the navigationService to assign back to the args // so that we can change the navigationController.scope from within the umbTree directive. Hrm. args.scope = scope; @@ -225,6 +226,9 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo //Set the current action node (this is not the same as the current selected node!) appState.setMenuState("currentNode", args.node); + //TODO: what the heck is going on here? - this seems really zany, allowing us to modify the + // navigationController.scope from within the navigationService to assign back to the args + // so that we can change the navigationController.scope from within the umbTree directive. Hrm. args.scope = scope; if (args.event && args.event.altKey) { @@ -238,7 +242,9 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo ev.stopPropagation(); ev.preventDefault(); - scope.currentNode = args.node; + //TODO: what the heck is going on here? - this seems really zany, allowing us to modify the + // navigationController.scope from within the navigationService to assign back to the args + // so that we can change the navigationController.scope from within the umbTree directive. Hrm. args.scope = scope; args.skipDefault = true; @@ -252,9 +258,6 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo ev.stopPropagation(); ev.preventDefault(); - //put this into the app state - appState.setTreeState("selectedNode", args.node); - if (n.metaData && n.metaData["jsClickCallback"] && angular.isString(n.metaData["jsClickCallback"]) && n.metaData["jsClickCallback"] !== "") { //this is a legacy tree node! var jsPrefix = "javascript:"; @@ -279,9 +282,11 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo else if (n.routePath) { //add action to the history service 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. + + //put this node into the tree state + appState.setTreeState("selectedNode", args.node); - ui.currentNode = n; + //not legacy, lets just set the route value and clear the query string if there is one. $location.path(n.routePath).search(""); } else if (args.element.section) { @@ -307,6 +312,7 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo * @param {String} args.tree the tree alias to sync to * @param {Array} args.path the path to sync the tree to * @param {Boolean} args.forceReload optional, specifies whether to force reload the node data from the server even if it already exists in the tree currently + * @param {Boolean} args.activate optional, specifies whether to set the synced node to be the active node, this will default to true if not specified */ syncTree: function (args) { if (!args) { 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 cd94e15087..f8266168b1 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 @@ -494,6 +494,29 @@ function treeService($q, treeResource, iconHelper, notificationsService, $rootSc return deferred.promise; }, + /** This will return the current node's path by walking up the tree */ + getPath: function(node) { + if (!node) { + throw "node cannot be null"; + } + if (!angular.isFunction(node.parent)) { + throw "node.parent is not a function, the path cannot be resolved"; + } + //all root nodes have metadata key 'treeAlias' + var reversePath = []; + var current = node; + while (current != null) { + reversePath.push(current.id); + if (current.metaData && current.metaData["treeAlias"]) { + current = null; + } + else { + current = current.parent(); + } + } + return reversePath.reverse(); + }, + syncTree: function(args) { if (!args) { @@ -569,7 +592,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, $rootSc } } else { - //the current node doesn't have it's children loaded, so go get them + //couldn't find it in the self.loadNodeChildren({ node: node, section: node.section }).then(function () { //ok, got the children, let's find it var found = self.getChildNode(node, args.path[currPathIndex]); diff --git a/src/Umbraco.Web.UI.Client/src/views/content/content.copy.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/content.copy.controller.js index 486c1dda10..27a4bf0046 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/content.copy.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/content.copy.controller.js @@ -1,6 +1,6 @@ angular.module("umbraco") .controller("Umbraco.Editors.Content.CopyController", - function ($scope, eventsService, contentResource, navigationService, $log) { + function ($scope, eventsService, contentResource, navigationService, appState, treeService) { var dialogOptions = $scope.$parent.dialogOptions; $scope.dialogTreeEventHandler = $({}); @@ -37,7 +37,19 @@ angular.module("umbraco") $scope.error = false; $scope.success = true; - navigationService.syncTree({ tree: "content", path: path, forceReload: true }); + //get the currently edited node (if any) + var activeNode = appState.getTreeState("selectedNode"); + + //we need to do a double sync here: first sync to the copied content - but don't activate the node, + //then sync to the currenlty edited content (note: this might not be the content that was copied!!) + + navigationService.syncTree({ tree: "content", path: path, forceReload: true, activate: false }).then(function(args) { + if (activeNode) { + var activeNodePath = treeService.getPath(activeNode).join(); + //sync to this node now - depending on what was copied this might already be synced but might not be + navigationService.syncTree({ tree: "content", path: activeNodePath, forceReload: false, activate: true }); + } + }); },function(err){ $scope.success = false; diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index a5fe178f34..6b3fdb1649 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Formatting; +using System.Text; using System.Web.Http; using System.Web.Http.ModelBinding; using AutoMapper; @@ -112,10 +113,14 @@ namespace Umbraco.Web.Editors /// /// /// - public string GetNiceUrl(int id) + public HttpResponseMessage GetNiceUrl(int id) { var url = Umbraco.NiceUrl(id); - return url; + var response = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent(url, Encoding.UTF8, "application/json") + }; + return response; } /// @@ -458,12 +463,17 @@ namespace Umbraco.Web.Editors /// /// [EnsureUserPermissionForContent("move.ParentId", 'M')] - public string PostMove(MoveOrCopy move) + public HttpResponseMessage PostMove(MoveOrCopy move) { var toMove = ValidateMoveOrCopy(move); Services.ContentService.Move(toMove, move.ParentId); - return toMove.Path; + + var response = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent(toMove.Path, Encoding.UTF8, "application/json") + }; + return response; } /// @@ -472,12 +482,17 @@ namespace Umbraco.Web.Editors /// /// [EnsureUserPermissionForContent("copy.ParentId", 'C')] - public string PostCopy(MoveOrCopy copy) + public HttpResponseMessage PostCopy(MoveOrCopy copy) { var toCopy = ValidateMoveOrCopy(copy); var c = Services.ContentService.Copy(toCopy, copy.ParentId, copy.RelateToOriginal); - return c.Path; + + var response = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent(c.Path, Encoding.UTF8, "application/json") + }; + return response; } /// diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index 4339f03484..844d8d5fc8 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -7,6 +7,7 @@ using System.Net.Http; using System.Net.Http.Formatting; using System.Net.Http.Headers; using System.Security.AccessControl; +using System.Text; using System.Threading.Tasks; using System.Web; using System.Web.Http; @@ -280,12 +281,15 @@ namespace Umbraco.Web.Editors [EnsureUserPermissionForMedia("move.Id")] public HttpResponseMessage PostMove(MoveOrCopy move) { - var toMove = ValidateMoveOrCopy(move); Services.MediaService.Move(toMove, move.ParentId); - return Request.CreateResponse(HttpStatusCode.OK); + var response = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent(toMove.Path, Encoding.UTF8, "application/json") + }; + return response; } ///