From b6dcbc83e4b328f2c5c08a5c16d67af7909f0acb Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 14 Nov 2013 18:50:31 +1100 Subject: [PATCH] Nearly got the whole nav.ui stuff taken care of, have most of the correct objects in appState, fixed up tree syncing with move dialog, fixed up state handling of the currently selected node, removed setting the navigationController's scope from within the navigationService (?), still some more stuff to clean up. --- .../lib/umbraco/LegacyUmbClientMgr.js | 21 ++++++---- .../common/directives/umbtree.directive.js | 40 ++++++++++--------- .../src/common/services/navigation.service.js | 28 ++++++++----- .../src/common/services/tree.service.js | 25 +++++++++++- .../views/content/content.copy.controller.js | 16 +++++++- src/Umbraco.Web/Editors/ContentController.cs | 27 ++++++++++--- src/Umbraco.Web/Editors/MediaController.cs | 8 +++- 7 files changed, 118 insertions(+), 47 deletions(-) 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; } ///