From 818c699d60dd11d47d412b92e6a2a5e956f5bdd6 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 8 Oct 2014 14:26:18 +1100 Subject: [PATCH] WIP: working on tree picker with search for list views. updates all pickers to ensure that they unbind any events. --- .../directives/umbtreeitem.directive.js | 310 +++++++++--------- .../directives/util/focuswhen.directive.js | 12 + src/Umbraco.Web.UI.Client/src/less/forms.less | 14 +- src/Umbraco.Web.UI.Client/src/less/tree.less | 5 + .../dialogs/contentpicker.controller.js | 127 +++---- .../common/dialogs/linkpicker.controller.js | 161 ++++----- .../dialogs/membergrouppicker.controller.js | 9 +- .../common/dialogs/memberpicker.controller.js | 8 +- .../common/dialogs/treepicker.controller.js | 77 ++++- .../src/views/common/dialogs/treepicker.html | 41 ++- .../views/content/content.copy.controller.js | 10 +- .../src/views/media/media.move.controller.js | 104 +++--- .../Trees/ContentTreeController.cs | 4 + 13 files changed, 513 insertions(+), 369 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/common/directives/util/focuswhen.directive.js diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/umbtreeitem.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/umbtreeitem.directive.js index 876b972ad1..b225ccaa44 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/umbtreeitem.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/umbtreeitem.directive.js @@ -18,166 +18,176 @@ */ angular.module("umbraco.directives") -.directive('umbTreeItem', function ($compile, $http, $templateCache, $interpolate, $log, $location, $rootScope, $window, treeService, $timeout) { - return { - restrict: 'E', - replace: true, +.directive('umbTreeItem', function ($compile, $http, $templateCache, $interpolate, $log, $location, $rootScope, $window, treeService, $timeout, localizationService) { + return { + restrict: 'E', + replace: true, - scope: { - section: '@', - cachekey: '@', - eventhandler: '=', - currentNode:'=', - node:'=', - tree:'=' - }, + scope: { + section: '@', + cachekey: '@', + eventhandler: '=', + currentNode: '=', + node: '=', + tree: '=' + }, - template: '
  • ' + - '' + - '' + - '' + - '' + - '' + - '
    ' + - '
    ' + - '
  • ', + template: '
  • ' + + '' + + '' + + '' + + '' + + '' + + '' + + '
    ' + + '
    ' + + '
  • ', - link: function (scope, element, attrs) { - - //flag to enable/disable delete animations, default for an item is tru - var deleteAnimations = true; + link: function (scope, element, attrs) { - /** Helper function to emit tree events */ - function emitEvent(eventName, args) { - if(scope.eventhandler){ - $(scope.eventhandler).trigger(eventName,args); - } - } + localizationService.localize("general_search").then(function (value) { + scope.searchAltText = value; + }); - /** updates the node's styles */ - function styleNode(node) { - node.stateCssClass = (node.cssClasses || []).join(" "); + //flag to enable/disable delete animations, default for an item is tru + var deleteAnimations = true; - if (node.style) { - $(element).find("i:first").attr("style", node.style); + /** Helper function to emit tree events */ + function emitEvent(eventName, args) { + if (scope.eventhandler) { + $(scope.eventhandler).trigger(eventName, args); + } } - } - /** This will deleteAnimations to true after the current digest */ - function enableDeleteAnimations() { - //do timeout so that it re-enables them after this digest - $timeout(function () { - //enable delete animations - deleteAnimations = true; - }, 0, false); - } + /** updates the node's styles */ + function styleNode(node) { + node.stateCssClass = (node.cssClasses || []).join(" "); + + if (node.style) { + $(element).find("i:first").attr("style", node.style); + } + } + + /** This will deleteAnimations to true after the current digest */ + function enableDeleteAnimations() { + //do timeout so that it re-enables them after this digest + $timeout(function () { + //enable delete animations + deleteAnimations = true; + }, 0, false); + } + + //add a method to the node which we can use to call to update the node data if we need to , + // this is done by sync tree, we don't want to add a $watch for each node as that would be crazy insane slow + // so we have to do this + scope.node.updateNodeData = function (newNode) { + _.extend(scope.node, newNode); + //now update the styles + styleNode(scope.node); + }; + + /** + Method called when the options button next to a node is called + In the main tree this opens the menu, but internally the tree doesnt + know about this, so it simply raises an event to tell the parent controller + about it. + */ + scope.options = function (n, ev) { + emitEvent("treeOptionsClick", { element: element, tree: scope.tree, node: n, event: ev }); + }; + + /** + Method called when an item is clicked in the tree, this passes the + DOM element, the tree node object and the original click + and emits it as a treeNodeSelect element if there is a callback object + defined on the tree + */ + scope.select = function (n, ev) { + emitEvent("treeNodeSelect", { element: element, tree: scope.tree, node: n, event: ev }); + }; + + /** + Method called when an item is right-clicked in the tree, this passes the + DOM element, the tree node object and the original click + and emits it as a treeNodeSelect element if there is a callback object + defined on the tree + */ + scope.altSelect = function (n, ev) { + emitEvent("treeNodeAltSelect", { element: element, tree: scope.tree, node: n, event: ev }); + }; + + scope.searchNode = function (n, ev) { + emitEvent("treeNodeSearch", { element: element, tree: scope.tree, node: n, event: ev }); + }; + + /** method to set the current animation for the node. + * This changes dynamically based on if we are changing sections or just loading normal tree data. + * When changing sections we don't want all of the tree-ndoes to do their 'leave' animations. + */ + scope.animation = function () { + if (deleteAnimations && scope.node.expanded) { + return { leave: 'tree-node-delete-leave' }; + } + else { + return {}; + } + }; + + /** + Method called when a node in the tree is expanded, when clicking the arrow + takes the arrow DOM element and node data as parameters + emits treeNodeCollapsing event if already expanded and treeNodeExpanding if collapsed + */ + scope.load = function (node) { + if (node.expanded) { + deleteAnimations = false; + emitEvent("treeNodeCollapsing", { tree: scope.tree, node: node, element: element }); + node.expanded = false; + } + else { + scope.loadChildren(node, false); + } + }; + + /* helper to force reloading children of a tree node */ + scope.loadChildren = function (node, forceReload) { + //emit treeNodeExpanding event, if a callback object is set on the tree + emitEvent("treeNodeExpanding", { tree: scope.tree, node: node }); + + if (node.hasChildren && (forceReload || !node.children || (angular.isArray(node.children) && node.children.length === 0))) { + //get the children from the tree service + treeService.loadNodeChildren({ node: node, section: scope.section }) + .then(function (data) { + //emit expanded event + emitEvent("treeNodeExpanded", { tree: scope.tree, node: node, children: data }); + enableDeleteAnimations(); + }); + } + else { + emitEvent("treeNodeExpanded", { tree: scope.tree, node: node, children: node.children }); + node.expanded = true; + enableDeleteAnimations(); + } + }; + + /** + Helper method for setting correct element padding on tree DOM elements + Since elements are not children of eachother, we need this indenting done + manually + */ + scope.setTreePadding = function (node) { + return { 'padding-left': (node.level * 20) + "px" }; + }; + + //if the current path contains the node id, we will auto-expand the tree item children - //add a method to the node which we can use to call to update the node data if we need to , - // this is done by sync tree, we don't want to add a $watch for each node as that would be crazy insane slow - // so we have to do this - scope.node.updateNodeData = function (newNode) { - _.extend(scope.node, newNode); - //now update the styles styleNode(scope.node); - }; - /** - Method called when the options button next to a node is called - In the main tree this opens the menu, but internally the tree doesnt - know about this, so it simply raises an event to tell the parent controller - about it. - */ - scope.options = function(e, n, ev){ - emitEvent("treeOptionsClick", {element: e, tree: scope.tree, node: n, event: ev}); - }; + var template = ''; + var newElement = angular.element(template); + $compile(newElement)(scope); + element.append(newElement); - /** - Method called when an item is clicked in the tree, this passes the - DOM element, the tree node object and the original click - and emits it as a treeNodeSelect element if there is a callback object - defined on the tree - */ - scope.select = function(e,n,ev){ - emitEvent("treeNodeSelect", { element: e, tree: scope.tree, node: n, event: ev }); - }; - - /** - Method called when an item is right-clicked in the tree, this passes the - DOM element, the tree node object and the original click - and emits it as a treeNodeSelect element if there is a callback object - defined on the tree - */ - scope.altSelect = function(e,n,ev){ - emitEvent("treeNodeAltSelect", { element: e, tree: scope.tree, node: n, event: ev }); - }; - - /** method to set the current animation for the node. - * This changes dynamically based on if we are changing sections or just loading normal tree data. - * When changing sections we don't want all of the tree-ndoes to do their 'leave' animations. - */ - scope.animation = function () { - if (deleteAnimations && scope.node.expanded) { - return { leave: 'tree-node-delete-leave' }; - } - else { - return {}; - } - }; - - /** - Method called when a node in the tree is expanded, when clicking the arrow - takes the arrow DOM element and node data as parameters - emits treeNodeCollapsing event if already expanded and treeNodeExpanding if collapsed - */ - scope.load = function(node) { - if (node.expanded) { - deleteAnimations = false; - emitEvent("treeNodeCollapsing", {tree: scope.tree, node: node }); - node.expanded = false; - } - else { - scope.loadChildren(node, false); - } - }; - - /* helper to force reloading children of a tree node */ - scope.loadChildren = function(node, forceReload){ - //emit treeNodeExpanding event, if a callback object is set on the tree - emitEvent("treeNodeExpanding", { tree: scope.tree, node: node }); - - if (node.hasChildren && (forceReload || !node.children || (angular.isArray(node.children) && node.children.length === 0))) { - //get the children from the tree service - treeService.loadNodeChildren({ node: node, section: scope.section }) - .then(function(data) { - //emit expanded event - emitEvent("treeNodeExpanded", {tree: scope.tree, node: node, children: data }); - enableDeleteAnimations(); - }); - } - else { - emitEvent("treeNodeExpanded", { tree: scope.tree, node: node, children: node.children }); - node.expanded = true; - enableDeleteAnimations(); - } - }; - - /** - Helper method for setting correct element padding on tree DOM elements - Since elements are not children of eachother, we need this indenting done - manually - */ - scope.setTreePadding = function(node) { - return { 'padding-left': (node.level * 20) + "px" }; - }; - - //if the current path contains the node id, we will auto-expand the tree item children - - styleNode(scope.node); - - var template = ''; - var newElement = angular.element(template); - $compile(newElement)(scope); - element.append(newElement); - } - }; + } + }; }); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/util/focuswhen.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/util/focuswhen.directive.js new file mode 100644 index 0000000000..7422dcfc35 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/util/focuswhen.directive.js @@ -0,0 +1,12 @@ +angular.module("umbraco.directives").directive('focusWhen', function ($timeout) { + return { + restrict: 'A', + link: function (scope, elm, attrs, ctrl) { + attrs.$observe("focusWhen", function (newValue) { + if (newValue === "true") { + elm.focus(); + } + }); + } + }; +}); diff --git a/src/Umbraco.Web.UI.Client/src/less/forms.less b/src/Umbraco.Web.UI.Client/src/less/forms.less index 5ecefa57e0..38f0f5fb2b 100644 --- a/src/Umbraco.Web.UI.Client/src/less/forms.less +++ b/src/Umbraco.Web.UI.Client/src/less/forms.less @@ -48,6 +48,19 @@ label.control-label { position: relative; padding: 0; } +.form-search a{ + text-decoration:none; + color: @grayLight; +} +.form-search a:hover{ + color: @gray; +} +.form-search h4 { + color: @gray; +} +.form-search small { + color: @grayLight; +} .form-search .icon-search { position: absolute; top: 6px; @@ -58,7 +71,6 @@ label.control-label { width: 90%; font-size: @fontSizeLarge; font-weight: 400; - color: @gray; border: 1px solid @grayLight; padding: 4px 0px 4px 16px; padding-left: 25px !Important; diff --git a/src/Umbraco.Web.UI.Client/src/less/tree.less b/src/Umbraco.Web.UI.Client/src/less/tree.less index 461e43c8b0..4217832121 100644 --- a/src/Umbraco.Web.UI.Client/src/less/tree.less +++ b/src/Umbraco.Web.UI.Client/src/less/tree.less @@ -145,6 +145,11 @@ padding-left: 35px; } +.umb-tree .umb-tree-node-search { + cursor:pointer; + /*color:@turquoise;*/ +} + a.umb-options { visibility: hidden; cursor: pointer; diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/contentpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/contentpicker.controller.js index 2919fb537f..949c75f983 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/contentpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/contentpicker.controller.js @@ -3,76 +3,81 @@ //used for the content picker dialog angular.module("umbraco").controller("Umbraco.Dialogs.ContentPickerController", - function ($scope, eventsService, entityResource, searchService, $log) { - var dialogOptions = $scope.dialogOptions; - $scope.dialogTreeEventHandler = $({}); - $scope.results = []; + function ($scope, eventsService, entityResource, searchService, $log) { + var dialogOptions = $scope.dialogOptions; + $scope.dialogTreeEventHandler = $({}); + $scope.results = []; - $scope.selectResult = function(result){ - entityResource.getById(result.id, "Document").then(function(ent){ - if(dialogOptions && dialogOptions.multiPicker){ - - $scope.showSearch = false; - $scope.results = []; - $scope.term = ""; - $scope.oldTerm = undefined; + $scope.selectResult = function (result) { + entityResource.getById(result.id, "Document").then(function (ent) { + if (dialogOptions && dialogOptions.multiPicker) { - $scope.select(ent); - }else{ - $scope.submit(ent); - } - }); - }; + $scope.showSearch = false; + $scope.results = []; + $scope.term = ""; + $scope.oldTerm = undefined; - $scope.performSearch = function(){ - if($scope.term){ - if($scope.oldTerm !== $scope.term){ - $scope.results = []; - searchService.searchContent({ term: $scope.term }).then(function(data) { - $scope.results = data; - }); - $scope.showSearch = true; - $scope.oldTerm = $scope.term; - } - }else{ - $scope.oldTerm = ""; - $scope.showSearch = false; - $scope.results = []; - } - }; + $scope.select(ent); + } else { + $scope.submit(ent); + } + }); + }; + $scope.performSearch = function () { + if ($scope.term) { + if ($scope.oldTerm !== $scope.term) { + $scope.results = []; + searchService.searchContent({ term: $scope.term }).then(function (data) { + $scope.results = data; + }); + $scope.showSearch = true; + $scope.oldTerm = $scope.term; + } + } else { + $scope.oldTerm = ""; + $scope.showSearch = false; + $scope.results = []; + } + }; - $scope.dialogTreeEventHandler.bind("treeNodeSelect", function(ev, args){ - args.event.preventDefault(); - args.event.stopPropagation(); + function nodeSelectHandler (ev, args) { + args.event.preventDefault(); + args.event.stopPropagation(); - eventsService.emit("dialogs.contentPicker.select", args); - - if (dialogOptions && dialogOptions.multiPicker) { + eventsService.emit("dialogs.contentPicker.select", args); - var c = $(args.event.target.parentElement); - if (!args.node.selected) { - args.node.selected = true; + if (dialogOptions && dialogOptions.multiPicker) { - var temp = ""; - var icon = c.find("i.umb-tree-icon"); - if (icon.length > 0) { - icon.hide().after(temp); - } else { - c.prepend(temp); - } + var c = $(args.event.target.parentElement); + if (!args.node.selected) { + args.node.selected = true; - } else { - args.node.selected = false; - c.find(".temporary").remove(); - c.find("i.umb-tree-icon").show(); - } + var temp = ""; + var icon = c.find("i.umb-tree-icon"); + if (icon.length > 0) { + icon.hide().after(temp); + } else { + c.prepend(temp); + } - $scope.select(args.node); + } else { + args.node.selected = false; + c.find(".temporary").remove(); + c.find("i.umb-tree-icon").show(); + } - } else { - $scope.submit(args.node); - } + $scope.select(args.node); - }); -}); \ No newline at end of file + } else { + $scope.submit(args.node); + } + + } + + $scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler); + + $scope.$on('$destroy', function () { + $scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler); + }); + }); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/linkpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/linkpicker.controller.js index 49302ca946..2a6e822a22 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/linkpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/linkpicker.controller.js @@ -1,87 +1,92 @@ //used for the media picker dialog angular.module("umbraco").controller("Umbraco.Dialogs.LinkPickerController", function ($scope, eventsService, dialogService, entityResource, contentResource, mediaHelper, userService) { - var dialogOptions = $scope.dialogOptions; - - $scope.dialogTreeEventHandler = $({}); - $scope.target = {}; + var dialogOptions = $scope.dialogOptions; - if(dialogOptions.currentTarget){ - $scope.target = dialogOptions.currentTarget; + $scope.dialogTreeEventHandler = $({}); + $scope.target = {}; - //if we have a node ID, we fetch the current node to build the form data - if($scope.target.id){ + if (dialogOptions.currentTarget) { + $scope.target = dialogOptions.currentTarget; - if(!$scope.target.path) { - entityResource.getPath($scope.target.id, "Document").then(function (path) { - $scope.target.path = path; - //now sync the tree to this path - $scope.dialogTreeEventHandler.syncTree({ path: $scope.target.path, tree: "content" }); - }); - } + //if we have a node ID, we fetch the current node to build the form data + if ($scope.target.id) { - contentResource.getNiceUrl($scope.target.id).then(function(url){ - $scope.target.url = url; - }); - } - } + if (!$scope.target.path) { + entityResource.getPath($scope.target.id, "Document").then(function (path) { + $scope.target.path = path; + //now sync the tree to this path + $scope.dialogTreeEventHandler.syncTree({ path: $scope.target.path, tree: "content" }); + }); + } - $scope.switchToMediaPicker = function () { - userService.getCurrentUser().then(function(userData) { - dialogService.mediaPicker({ - startNodeId: userData.startMediaId, - callback: function (media) { - $scope.target.id = media.id; - $scope.target.isMedia = true; - $scope.target.name = media.name; - $scope.target.url = mediaHelper.resolveFile(media); - } - }); + contentResource.getNiceUrl($scope.target.id).then(function (url) { + $scope.target.url = url; + }); + } + } + + $scope.switchToMediaPicker = function () { + userService.getCurrentUser().then(function (userData) { + dialogService.mediaPicker({ + startNodeId: userData.startMediaId, + callback: function (media) { + $scope.target.id = media.id; + $scope.target.isMedia = true; + $scope.target.name = media.name; + $scope.target.url = mediaHelper.resolveFile(media); + } + }); + }); + }; + + function nodeSelectHandler (ev, args) { + args.event.preventDefault(); + args.event.stopPropagation(); + + eventsService.emit("dialogs.linkPicker.select", args); + + var c = $(args.event.target.parentElement); + + //renewing + if (args.node !== $scope.target) { + if ($scope.selectedEl) { + $scope.selectedEl.find(".temporary").remove(); + $scope.selectedEl.find("i.umb-tree-icon").show(); + } + + $scope.selectedEl = c; + $scope.target.id = args.node.id; + $scope.target.name = args.node.name; + + $scope.selectedEl.find("i.umb-tree-icon") + .hide() + .after(""); + + if (args.node.id < 0) { + $scope.target.url = "/"; + } else { + contentResource.getNiceUrl(args.node.id).then(function (url) { + $scope.target.url = url; + }); + } + } else { + $scope.target = undefined; + //resetting + if ($scope.selectedEl) { + $scope.selectedEl.find(".temporary").remove(); + $scope.selectedEl.find("i.umb-tree-icon").show(); + } + } + + if (!angular.isUndefined($scope.target.isMedia)) { + delete $scope.target.isMedia; + } + } + + $scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler); + + $scope.$on('$destroy', function () { + $scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler); }); - }; - - - $scope.dialogTreeEventHandler.bind("treeNodeSelect", function(ev, args){ - args.event.preventDefault(); - args.event.stopPropagation(); - - eventsService.emit("dialogs.linkPicker.select", args); - - var c = $(args.event.target.parentElement); - - //renewing - if (args.node !== $scope.target) { - if ($scope.selectedEl) { - $scope.selectedEl.find(".temporary").remove(); - $scope.selectedEl.find("i.umb-tree-icon").show(); - } - - $scope.selectedEl = c; - $scope.target.id = args.node.id; - $scope.target.name = args.node.name; - - $scope.selectedEl.find("i.umb-tree-icon") - .hide() - .after(""); - - if (args.node.id < 0) { - $scope.target.url = "/"; - } else { - contentResource.getNiceUrl(args.node.id).then(function (url) { - $scope.target.url = url; - }); - } - } else { - $scope.target = undefined; - //resetting - if ($scope.selectedEl) { - $scope.selectedEl.find(".temporary").remove(); - $scope.selectedEl.find("i.umb-tree-icon").show(); - } - } - - if (!angular.isUndefined($scope.target.isMedia)) { - delete $scope.target.isMedia; - } - }); -}); \ No newline at end of file + }); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/membergrouppicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/membergrouppicker.controller.js index 6fda9e9e5d..985ac52169 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/membergrouppicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/membergrouppicker.controller.js @@ -34,8 +34,7 @@ angular.module("umbraco").controller("Umbraco.Dialogs.MemberGroupPickerControlle } } - - $scope.dialogTreeEventHandler.bind("treeNodeSelect", function(ev, args) { + function nodeSelectHandler(ev, args) { args.event.preventDefault(); args.event.stopPropagation(); @@ -63,5 +62,11 @@ angular.module("umbraco").controller("Umbraco.Dialogs.MemberGroupPickerControlle } } + } + + $scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler); + + $scope.$on('$destroy', function () { + $scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler); }); }); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/memberpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/memberpicker.controller.js index 25c68a3dcd..f77f63dd05 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/memberpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/memberpicker.controller.js @@ -54,7 +54,7 @@ angular.module("umbraco").controller("Umbraco.Dialogs.MemberPickerController", select(result.name, result.id, result); }; - $scope.dialogTreeEventHandler.bind("treeNodeSelect", function(ev, args) { + function nodeSelectHandler(ev, args) { args.event.preventDefault(); args.event.stopPropagation(); @@ -83,5 +83,11 @@ angular.module("umbraco").controller("Umbraco.Dialogs.MemberPickerController", } } + } + + $scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler); + + $scope.$on('$destroy', function () { + $scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler); }); }); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/treepicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/treepicker.controller.js index a1be877c26..22b9119ad2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/treepicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/treepicker.controller.js @@ -1,6 +1,6 @@ //used for the media picker dialog angular.module("umbraco").controller("Umbraco.Dialogs.TreePickerController", - function ($scope, entityResource, eventsService, $log, searchService, angularHelper) { + function ($scope, entityResource, eventsService, $log, searchService, angularHelper, $timeout, localizationService) { var dialogOptions = $scope.dialogOptions; $scope.dialogTreeEventHandler = $({}); @@ -9,7 +9,10 @@ angular.module("umbraco").controller("Umbraco.Dialogs.TreePickerController", $scope.multiPicker = dialogOptions.multiPicker; $scope.hideHeader = true; $scope.startNodeId = dialogOptions.startNodeId ? dialogOptions.startNodeId : -1; - + localizationService.localize("general_typeToSearch").then(function (value) { + $scope.searchPlaceholderText = value; + }); + $scope.selectedSearchResults = []; //create the custom query string param for this tree $scope.customTreeParams = dialogOptions.startNodeId ? "startNodeId=" + dialogOptions.startNodeId : ""; $scope.customTreeParams += dialogOptions.customTreeParams ? "&" + dialogOptions.customTreeParams : ""; @@ -52,14 +55,28 @@ angular.module("umbraco").controller("Umbraco.Dialogs.TreePickerController", if (dialogOptions.filter[0] === "{") { dialogOptions.filterAdvanced = true; } - - $scope.dialogTreeEventHandler.bind("treeNodeExpanded", function (ev, args) { - if (angular.isArray(args.children)) { - performFiltering(args.children); - } - }); } + function nodeSearchHandler(ev, args) { + if (args.node.metaData.isContainer === true) { + $scope.showSearch = true; + $scope.searchSubHeader = args.node.name; + } + } + + function nodeExpandedHandler(ev, args) { + if (angular.isArray(args.children)) { + //check filter + if (dialogOptions.filter) { + performFiltering(args.children); + } + } + } + + $scope.dialogTreeEventHandler.bind("treeNodeSearch", nodeSearchHandler); + + $scope.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler); + /** Method used for selecting a node */ function select(text, id, entity) { @@ -78,14 +95,22 @@ angular.module("umbraco").controller("Umbraco.Dialogs.TreePickerController", $scope.submit(node); } } else { - $scope.showSearch = false; - $scope.results = []; - $scope.term = ""; - $scope.oldTerm = undefined; - + if ($scope.multiPicker) { $scope.select(id); - } else { + + if (!$scope.searchSubHeader) { + $scope.hideSearch(); + } + } + else { + + $scope.results = []; + $scope.term = ""; + $scope.oldTerm = undefined; + + $scope.hideSearch(); + //if an entity has been passed in, use it if (entity) { $scope.submit(entity); @@ -139,6 +164,10 @@ angular.module("umbraco").controller("Umbraco.Dialogs.TreePickerController", select(result.name, result.id, result); }; + $scope.hideSearch = function() { + $scope.showSearch = false; + $scope.searchSubHeader = null; + } //handles the on key up for searching, but we don't want to over query so the result is debounced $scope.performSearch = _.debounce(function () { @@ -162,16 +191,20 @@ angular.module("umbraco").controller("Umbraco.Dialogs.TreePickerController", } } else { - $scope.oldTerm = ""; - $scope.showSearch = false; - $scope.results = []; + + //if (!$scope.searchSubHeader) { + // $scope.oldTerm = ""; + // $scope.hideSearch(); + // $scope.results = []; + //} + } }); }, 200); //wires up selection - $scope.dialogTreeEventHandler.bind("treeNodeSelect", function (ev, args) { + function nodeSelectHandler(ev, args) { args.event.preventDefault(); args.event.stopPropagation(); @@ -205,5 +238,13 @@ angular.module("umbraco").controller("Umbraco.Dialogs.TreePickerController", c.find("i.umb-tree-icon").show(); } } + } + + $scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler); + + $scope.$on('$destroy', function () { + $scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler); + $scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler); + $scope.dialogTreeEventHandler.unbind("treeNodeSearch", nodeSearchHandler); }); }); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/treepicker.html b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/treepicker.html index e00ecddbce..57c4271fa9 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/treepicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/treepicker.html @@ -2,20 +2,47 @@
    -
    +