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 e164a0bc73..b08476ee77 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 @@ -35,14 +35,12 @@ angular.module("umbraco.directives") // this will greatly improve performance since there's potentially a lot of nodes being rendered = a LOT of watches! template: '
  • ' + - '
    ' + + '
    ' + //NOTE: This ins element is used to display the search icon if the node is a container/listview and the tree is currently in dialog //'' + '' + '' + - //NOTE: If the tree supports check boxes, render different markup - '' + - '' + + '' + '' + //NOTE: These are the 'option' elipses '' + @@ -56,25 +54,23 @@ angular.module("umbraco.directives") scope.searchAltText = value; }); - //flag to enable/disable delete animations, default for an item is tru + //flag to enable/disable delete animations, default for an item is true var deleteAnimations = true; - /** Helper function to emit tree events */ + // Helper function to emit tree events function emitEvent(eventName, args) { if (scope.eventhandler) { $(scope.eventhandler).trigger(eventName, args); } } - /** updates the node's DOM/styles */ + // updates the node's DOM/styles function setupNodeDom(node, tree) { //get the first div element element.children(":first") //set the padding - .css("padding-left", (node.level * 20) + "px") - //set the class - .addClass((node.cssClasses || []).join(" ")); + .css("padding-left", (node.level * 20) + "px"); //remove first 'ins' if there is no children //show/hide last 'ins' depending on children @@ -85,17 +81,10 @@ angular.module("umbraco.directives") else { element.find("ins").last().show(); } - - //add/remove 'i' depending on enablecheckboxes - if (tree.enablecheckboxes === "true") { - element.find("i").eq(1).remove(); - } - else if (!tree.enablecheckboxes || tree.enablecheckboxes === 'false') { - element.find("i:first").remove(); - element.find("i:first").addClass(node.cssClass); - } - //now set the title on the remaining icon - element.find("i:first").attr("title", node.routePath); + + var icon = element.find("i:first"); + icon.addClass(node.cssClass); + icon.attr("title", node.routePath); element.find("a:first").html(node.name); @@ -108,7 +97,7 @@ angular.module("umbraco.directives") } } - /** This will deleteAnimations to true after the current digest */ + //This will deleteAnimations to true after the current digest function enableDeleteAnimations() { //do timeout so that it re-enables them after this digest $timeout(function () { @@ -117,12 +106,21 @@ angular.module("umbraco.directives") }, 0, false); } - scope.selectEnabledNodeClass = function (node) { - return node ? - node.selected ? - 'icon umb-tree-icon sprTree icon-check blue temporary' : - node.cssClass : - ''; + /** Returns the css classses assigned to the node (div element) */ + scope.getNodeCssClass = function (node) { + if (!node) { + return ''; + } + var css = []; + if (node.cssClasses) { + _.each(node.cssClasses, function(c) { + css.push(c); + }); + } + if (node.selected) { + css.push("umb-tree-node-checked"); + } + return css.join(" "); }; //add a method to the node which we can use to call to update the node data if we need to , @@ -169,6 +167,9 @@ angular.module("umbraco.directives") * When changing sections we don't want all of the tree-ndoes to do their 'leave' animations. */ scope.animation = function () { + if (scope.node.showHideAnimation) { + return scope.node.showHideAnimation; + } if (deleteAnimations && scope.node.expanded) { return { leave: 'tree-node-delete-leave' }; } diff --git a/src/Umbraco.Web.UI.Client/src/less/animations.less b/src/Umbraco.Web.UI.Client/src/less/animations.less index 20cb52b109..ee17d37194 100644 --- a/src/Umbraco.Web.UI.Client/src/less/animations.less +++ b/src/Umbraco.Web.UI.Client/src/less/animations.less @@ -145,3 +145,47 @@ .tree-node-delete-leave * { color:@red !important; } + + +.tree-node-slide-up +{ + opacity:1; + top: 0px; + -webkit-transition: 700ms cubic-bezier(0.000, 0.000, 0.580, 1.000) all; + -moz-transition: 700ms cubic-bezier(0.000, 0.000, 0.580, 1.000) all; + -ms-transition: 700ms cubic-bezier(0.000, 0.000, 0.580, 1.000) all; + -o-transition: 700ms cubic-bezier(0.000, 0.000, 0.580, 1.000) all; + transition: 700ms cubic-bezier(0.000, 0.000, 0.580, 1.000) all; +} +.tree-node-slide-up * { + font-size:100%; + -webkit-transition:font-size 700ms; + -moz-transition:font-size 700ms; + -ms-transition:font-size 700ms; + -o-transition:font-size 700ms; + transition:font-size 700ms; +} +.tree-node-slide-up.tree-node-slide-up-hide-active { + opacity: 0; + top: -100px; +} +.tree-node-slide-up.tree-node-slide-up-hide-active * { + font-size:120%; +} + +.tree-fade-out-hide , +.tree-fade-out-show, +.tree-fade-out-hide div:not(.tree-node-slide-up-hide-active), +.tree-fade-out-show div:not(.tree-node-slide-up-hide-active) { + -webkit-transition: 700ms cubic-bezier(0.075, 0.820, 0.165, 1.000) all; + -moz-transition: 700ms cubic-bezier(0.075, 0.820, 0.165, 1.000) all; + -ms-transition: 700ms cubic-bezier(0.075, 0.820, 0.165, 1.000) all; + -o-transition: 700ms cubic-bezier(0.075, 0.820, 0.165, 1.000) all; + transition: 700ms cubic-bezier(0.075, 0.820, 0.165, 1.000) all; +} +.tree-fade-out-show.tree-fade-out-show-active div:not(.tree-node-slide-up-hide-active){ + opacity: 1; +} +.tree-fade-out-hide.tree-fade-out-hide-active div:not(.tree-node-slide-up-hide-active){ + opacity: 0; +} \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/less/belle.less b/src/Umbraco.Web.UI.Client/src/less/belle.less index bde8007760..1e2e655043 100644 --- a/src/Umbraco.Web.UI.Client/src/less/belle.less +++ b/src/Umbraco.Web.UI.Client/src/less/belle.less @@ -70,13 +70,13 @@ @import "modals.less"; @import "panel.less"; @import "sections.less"; +@import "helveticons.less"; @import "main.less"; @import "tree.less"; @import "listview.less"; @import "gridview.less"; @import "footer.less"; @import "animations.less"; -@import "helveticons.less"; @import "dragdrop.less"; //used for property editors diff --git a/src/Umbraco.Web.UI.Client/src/less/tree.less b/src/Umbraco.Web.UI.Client/src/less/tree.less index 21b451ea9f..77223a906a 100644 --- a/src/Umbraco.Web.UI.Client/src/less/tree.less +++ b/src/Umbraco.Web.UI.Client/src/less/tree.less @@ -150,6 +150,18 @@ /*color:@turquoise;*/ } +.icon-check:before { + content: "\e165"; +} + +.umb-tree .umb-tree-node-checked i { + color:@blue !important; +} +.umb-tree .umb-tree-node-checked i:before { + /*check box*/ + content: "\e165" !important; +} + a.umb-options { visibility: hidden; cursor: pointer; @@ -224,6 +236,7 @@ li.root > div > a.umb-options { } + // Tree item states // ------------------------- div.not-published > i.icon,div.not-published > a{ 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 c49aad5d68..82bd91a016 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, $timeout, localizationService) { + function ($scope, entityResource, eventsService, $log, searchService, angularHelper, $timeout, localizationService, treeService) { var tree = null; var dialogOptions = $scope.dialogOptions; @@ -75,20 +75,25 @@ angular.module("umbraco").controller("Umbraco.Dialogs.TreePickerController", child.children = [ { level: child.level + 1, - hasChildren: false, + hasChildren: false, + parent: function () { + return child; + }, name: searchText, metaData: { listViewNode: child, }, - cssClass: "icon umb-tree-icon sprTree icon-search", + cssClass: "icon-search", cssClasses: ["not-published"] } ]; + //add base transition classes to this node + child.cssClasses.push("tree-node-slide-up"); + var listViewResults = _.filter($scope.searchInfo.selectedSearchResults, function(i) { return i.parentId == child.id; }); _.each(listViewResults, function(item) { - var parent = child; child.children.unshift({ id: item.id, name: item.name, @@ -99,7 +104,7 @@ angular.module("umbraco").controller("Umbraco.Dialogs.TreePickerController", }, hasChildren: false, parent: function () { - return parent; + return child; } }); }); @@ -138,6 +143,10 @@ angular.module("umbraco").controller("Umbraco.Dialogs.TreePickerController", $scope.searchInfo.showSearch = true; $scope.searchInfo.searchFromId = args.node.metaData.listViewNode.id; $scope.searchInfo.searchFromName = args.node.metaData.listViewNode.name; + + //add transition classes + var listViewNode = args.node.parent(); + listViewNode.cssClasses.push('tree-node-slide-up-hide-active'); } else if (args.node.metaData.isSearchResult) { //check if the item selected was a search result from a list view @@ -258,14 +267,20 @@ angular.module("umbraco").controller("Umbraco.Dialogs.TreePickerController", return i.id == result.id; }); } + + //ensure the tree node in the tree is checked/unchecked if it already exists there + if (tree) { + var found = treeService.getDescendantNode(tree.root, result.id); + if (found) { + found.selected = result.selected; + } + } + }; $scope.hideSearch = function () { - - //TODO: Move this to the treeService, we don't need a reference to the 'tree' the way this is working - // because if we have a single node, that is all we need since we can traverse to the tree root in the treeService. - // this logic needs to be centralized so it can be used in other tree + search areas. - + + //Traverse the entire displayed tree and update each node to sync with the selected search results if (tree) { //we need to ensure that any currently displayed nodes that get selected @@ -290,14 +305,15 @@ angular.module("umbraco").controller("Umbraco.Dialogs.TreePickerController", return c.id == child.id; }); } - else { - //it's not part of any search result, uncheck it - child.selected = false; - } - + //check if the current node is a list view and if so, check if there's any new results // that need to be added as child nodes to it based on search results selected if (child.metaData.isContainer) { + + child.cssClasses = _.reject(child.cssClasses, function(c) { + return c === 'tree-node-slide-up-hide-active'; + }); + var listViewResults = _.filter($scope.searchInfo.selectedSearchResults, function (i) { return i.parentId == child.id; }); 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 f72f35c0b7..3d39817680 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 @@ -17,22 +17,21 @@
    -
    - +
    +