diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/tree/umbtree.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/tree/umbtree.directive.js index 7055d1a746..cfc1cfbfd3 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/tree/umbtree.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/tree/umbtree.directive.js @@ -38,7 +38,7 @@ function umbTreeDirective($q, $rootScope, treeService, notificationsService, use treeOptionsClick: [], treeNodeAltSelect: [] }; - + //this is the API exposed by this directive, for either hosting controllers or for other directives vm.callbacks = { treeNodeExpanded: function (f) { @@ -82,7 +82,7 @@ function umbTreeDirective($q, $rootScope, treeService, notificationsService, use // since it saves on data retreival and DOM processing. // TODO: This isn't used!? var lastSection = ""; - + /** Helper function to emit tree events */ function emitEvent(eventName, args) { if (registeredCallbacks[eventName] && angular.isArray(registeredCallbacks[eventName])) { @@ -119,7 +119,7 @@ function umbTreeDirective($q, $rootScope, treeService, notificationsService, use $scope.cachekey = args.cacheKey; } } - + return loadTree(); } @@ -148,7 +148,7 @@ function umbTreeDirective($q, $rootScope, treeService, notificationsService, use if (!args.path) { throw "args.path cannot be null"; } - + if (angular.isString(args.path)) { args.path = args.path.replace('"', '').split(','); } @@ -172,8 +172,16 @@ function umbTreeDirective($q, $rootScope, treeService, notificationsService, use emitEvent("treeSynced", { node: data, activate: args.activate }); return $q.when({ node: data, activate: args.activate }); + }, function (data) { + return $q.reject(data); + }, function (data) { + //on notification + if (data.type === "treeNodeExpanded") { + //raise the event + emitEvent("treeNodeExpanded", { tree: $scope.tree, node: data.node, children: data.children }); + } }); - + } /** This will check the section tree loaded and return all actual root nodes based on a tree type (non group nodes, non section groups) */ @@ -201,7 +209,7 @@ function umbTreeDirective($q, $rootScope, treeService, notificationsService, use //given a tree alias, this will search the current section tree for the specified tree alias and set the current active tree to it's root node function loadActiveTree(treeAlias) { - + if (!$scope.tree) { throw "Err in umbtree.directive.loadActiveTree, $scope.tree is null"; } @@ -233,7 +241,7 @@ function umbTreeDirective($q, $rootScope, treeService, notificationsService, use function loadTree() { if (!$scope.loading && $scope.section) { $scope.loading = true; - + //default args var args = { section: $scope.section, tree: $scope.treealias, cacheKey: $scope.cachekey, isDialog: $scope.isdialog ? $scope.isdialog : false }; @@ -279,7 +287,7 @@ function umbTreeDirective($q, $rootScope, treeService, notificationsService, use if (forceReload || (node.hasChildren && node.children.length === 0)) { //get the children from the tree service return treeService.loadNodeChildren({ node: node, section: $scope.section, isDialog: $scope.isdialog }) - .then(function(data) { + .then(function (data) { //emit expanded event emitEvent("treeNodeExpanded", { tree: $scope.tree, node: node, children: data }); @@ -302,7 +310,7 @@ function umbTreeDirective($q, $rootScope, treeService, notificationsService, use // TODO: This is called constantly because as a method in a template it's re-evaluated pretty much all the time // it would be better if we could cache the processing. The problem is that some of these things are dynamic. - + var css = []; if (node.cssClasses) { _.each(node.cssClasses, function (c) { @@ -322,7 +330,7 @@ function umbTreeDirective($q, $rootScope, treeService, notificationsService, use }; /* helper to force reloading children of a tree node */ - $scope.loadChildren = function(node, forceReload) { + $scope.loadChildren = function (node, forceReload) { return loadChildren(node, forceReload); }; @@ -359,7 +367,7 @@ function umbTreeDirective($q, $rootScope, treeService, notificationsService, use $scope.altSelect = function (n, ev) { emitEvent("treeNodeAltSelect", { element: $element, tree: $scope.tree, node: n, event: ev }); }; - + //call the onInit method, if the result is a promise then load the tree after that resolves (if it's not a promise this will just resolve automatically). //NOTE: The promise cannot be rejected, else the tree won't be loaded and we'll get exceptions if some API calls syncTree or similar. $q.when($scope.onInit(), function (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 d61d1c3ba1..3e60b09ad9 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 @@ -41,7 +41,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS return { /** Internal method to return the tree cache */ - _getTreeCache: function() { + _getTreeCache: function () { return treeCache; }, @@ -97,7 +97,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS } //create a method outside of the loop to return the parent - otherwise jshint blows up - var funcParent = function() { + var funcParent = function () { return parentNode; }; @@ -168,7 +168,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS * * @param {String} treeAlias The tree alias to check */ - getTreePackageFolder: function(treeAlias) { + getTreePackageFolder: function (treeAlias) { //we determine this based on the server variables if (Umbraco.Sys.ServerVariables.umbracoPlugins && Umbraco.Sys.ServerVariables.umbracoPlugins.trees && @@ -220,7 +220,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS var self = this; this.clearCache({ cacheKey: args.cacheKey, - filter: function(cc) { + filter: function (cc) { //get the new parent node from the tree cache var parent = self.getDescendantNode(cc.root, args.childrenOf); if (parent) { @@ -288,7 +288,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS * @param {object} args.node The tree node * @param {object} args.section The current section */ - loadNodeChildren: function(args) { + loadNodeChildren: function (args) { if (!args) { throw "No args object defined for loadNodeChildren"; } @@ -303,7 +303,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS args.node.loading = true; return this.getChildren(args) - .then(function(data) { + .then(function (data) { //set state to done and expand (only if there actually are children!) args.node.loading = false; @@ -320,10 +320,10 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS return $q.when(data); - }, function(reason) { + }, function (reason) { //in case of error, emit event - eventsService.emit("treeService.treeNodeLoadError", {error: reason } ); + eventsService.emit("treeService.treeNodeLoadError", { error: reason }); //stop show the loading indicator args.node.loading = false; @@ -346,7 +346,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS * Removes a given node from the tree * @param {object} treeNode the node to remove */ - removeNode: function(treeNode) { + removeNode: function (treeNode) { if (!angular.isFunction(treeNode.parent)) { return; } @@ -359,7 +359,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS parent.children.splice(parent.children.indexOf(treeNode), 1); parent.hasChildren = parent.children.length !== 0; - + //Notify that the node has been removed eventsService.emit("treeService.removeNode", { node: treeNode }); }, @@ -374,7 +374,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS * Removes all child nodes from a given tree node * @param {object} treeNode the node to remove children from */ - removeChildNodes : function(treeNode) { + removeChildNodes: function (treeNode) { treeNode.expanded = false; treeNode.children = []; treeNode.hasChildren = false; @@ -413,7 +413,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS * @param {int} id id of descendant node * @param {string} treeAlias - optional tree alias, if fetching descendant node from a child of a listview document */ - getDescendantNode: function(treeNode, id, treeAlias) { + getDescendantNode: function (treeNode, id, treeAlias) { //validate if it is a section container since we'll need a treeAlias if it is one if (treeNode.isContainer === true && !treeAlias) { @@ -432,7 +432,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS var root = getTreeRoot(tn.children[c]); //only return if we found the root in this child, otherwise continue. - if(root){ + if (root) { return root; } } @@ -531,7 +531,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS * Gets the node's tree alias, this is done by looking up the meta-data of the current node's root node * @param {object} treeNode to retrive tree alias from */ - getTreeAlias : function(treeNode) { + getTreeAlias: function (treeNode) { var root = this.getTreeRoot(treeNode); if (root) { return root.metaData["treeAlias"]; @@ -570,7 +570,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS var self = this; return treeResource.loadApplication(args) - .then(function(data) { + .then(function (data) { //this will be called once the tree app data has loaded var result = { name: data.name, @@ -624,7 +624,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS } return treeResource.loadMenu(args.treeNode) - .then(function(data) { + .then(function (data) { //need to convert the icons to new ones for (var i = 0; i < data.length; i++) { data[i].cssclass = iconHelper.convertFromLegacyIcon(data[i].cssclass); @@ -677,7 +677,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS * Re-loads the single node from the server * @param {object} node Tree node to reload */ - reloadNode: function(node) { + reloadNode: function (node) { if (!node) { throw "node cannot be null"; } @@ -691,10 +691,10 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS //set the node to loading node.loading = true; - return this.getChildren({ node: node.parent(), section: node.section }).then(function(data) { + return 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) { + var found = _.find(data, function (item) { return item.id === node.id; }); if (found) { @@ -720,7 +720,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS else { return $q.reject(); } - }, function() { + }, function () { return $q.reject(); }); }, @@ -735,7 +735,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS * This will return the current node's path by walking up the tree * @param {object} node Tree node to retrieve path for */ - getPath: function(node) { + getPath: function (node) { if (!node) { throw "node cannot be null"; } @@ -760,7 +760,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS return reversePath.reverse(); }, - syncTree: function(args) { + syncTree: function (args) { if (!args) { throw "No args object defined for syncTree"; @@ -800,6 +800,8 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS } } + var deferred = $q.defer(); + //now that we have the first id to lookup, we can start the process var self = this; @@ -831,6 +833,10 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS else { //couldn't find it in the return self.loadNodeChildren({ node: node, section: node.section }).then(function (children) { + + //send back some progress to allow the caller to deal with expanded nodes + deferred.notify({ type: "treeNodeExpanded", node: node, children: children }) + //ok, got the children, let's find it var found = self.getChildNode(node, args.path[currPathIndex]); if (found) { @@ -858,8 +864,16 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS }; //start - return doSync(); + var wrappedPromise = doSync(); + //then wrap it + wrappedPromise.then(function (args) { + deferred.resolve(args); + }, function (args) { + deferred.reject(args); + }); + + return deferred.promise; } }; diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.controller.js index 915abf62b0..7ba6e71f0c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.controller.js @@ -59,6 +59,8 @@ angular.module("umbraco").controller("Umbraco.Editors.TreePickerController", vm.submit = submit; vm.close = close; + var currentNode = $scope.model.currentNode; + function initDialogTree() { vm.dialogTreeApi.callbacks.treeLoaded(treeLoadedHandler); // TODO: Also deal with unexpanding!! @@ -160,6 +162,12 @@ angular.module("umbraco").controller("Umbraco.Editors.TreePickerController", } } } + + vm.filter = { + filterAdvanced: $scope.model.filterAdvanced, + filterExclude: $scope.model.filterExclude, + filter: $scope.model.filter + }; } /** @@ -256,6 +264,12 @@ angular.module("umbraco").controller("Umbraco.Editors.TreePickerController", vm.hasItems = args.tree.root.children.length > 0; tree = args.tree; + + var nodeHasPath = currentNode && currentNode.path; + var startNodeNotDefined = !vm.startNodeId; + if (startNodeNotDefined && nodeHasPath) { + vm.dialogTreeApi.syncTree({ path: currentNode.path, activate: false }); + } } //wires up selection diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.html index c592b4ec3b..57ee805ba0 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/treepicker/treepicker.html @@ -74,7 +74,7 @@ start-node-id="vm.startNodeId" on-select="vm.selectListViewNode(node)" on-close="vm.closeMiniListView()" - entity-type-filter="filter"> + entity-type-filter="vm.filter"> diff --git a/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs b/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs index 2598523bd5..d5bc6adee9 100644 --- a/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs +++ b/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs @@ -45,10 +45,10 @@ namespace Umbraco.Web.Models.Mapping if (source.NodeObjectType == Constants.ObjectTypes.Member && target.Icon.IsNullOrWhiteSpace()) target.Icon = "icon-user"; - if (source.NodeObjectType == Constants.ObjectTypes.Media && source is IContentEntitySlim contentSlim) + if (source is IContentEntitySlim contentSlim) source.AdditionalData["ContentTypeAlias"] = contentSlim.ContentTypeAlias; - if (source.NodeObjectType == Constants.ObjectTypes.Media && source is IMediaEntitySlim mediaSlim) + if (source is IMediaEntitySlim mediaSlim) source.AdditionalData["MediaPath"] = mediaSlim.MediaPath; // NOTE: we're mapping the objects in AdditionalData by object reference here.