diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..514acd3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Steve + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/css/tree-control.css b/css/tree-control.css new file mode 100644 index 0000000..f5f8861 --- /dev/null +++ b/css/tree-control.css @@ -0,0 +1,109 @@ +treecontrol { + /* prevent user selection */ + -moz-user-select: -moz-none; + -khtml-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; + + /* default */ + font-family: Verdana, Helvetica, Arial, sans-serif; + font-size:13px; + color: #555; + text-decoration: none; +} + +treecontrol ul { + margin: 0; + padding: 0; + list-style: none; + border: none; + overflow: hidden; +} + +treecontrol li { + position: relative; + padding: 0 0 0 20px; + line-height: 20px; +} + +treecontrol li.tree-expanded i.tree-normal, treecontrol li.tree-collapsed i.tree-normal {display:none;} +treecontrol li.tree-expanded i.tree-has-children, treecontrol li.tree-collapsed i.tree-has-children {display:inline;} +treecontrol li.tree-normal i.tree-has-children {display:none;} +treecontrol li.tree-normal i.tree-normal {display:inline;} + +treecontrol li i { + cursor: pointer; +} + +treecontrol li .tree-label { + cursor: pointer; + display: inline; +} + + +treecontrol.tree-classic li.tree-expanded i { + padding: 1px 10px; + background: url("../images/folder.png") no-repeat; +} + +treecontrol.tree-classic li.tree-collapsed i { + padding: 1px 10px; + background: url("../images/folder-closed.png") no-repeat; +} + +treecontrol.tree-classic li.tree-normal i { + padding: 1px 10px; + background: url("../images/file.png") no-repeat; +} + +treecontrol.tree-classic li .tree-selected { + background-color: #aaddff; + font-weight: bold; +} + + +treecontrol.tree-light li.tree-expanded i { + padding: 1px 10px; + background: url("../images/node-opened-2.png") no-repeat; +} + +treecontrol.tree-light li.tree-collapsed i { + padding: 1px 10px; + background: url("../images/node-closed-2.png") no-repeat; +} + +treecontrol.tree-light li.tree-normal i { + padding: 1px 10px; + width: 16px; height: 16px; + background: none no-repeat; +} + +treecontrol.tree-light li .tree-selected { + font-weight: bold; +} + + +treecontrol.tree-dark li.tree-expanded i { + padding: 1px 10px; + background: url("../images/node-opened-light.png") no-repeat; +} + +treecontrol.tree-dark li.tree-collapsed i { + padding: 1px 10px; + background: url("../images/node-closed-light.png") no-repeat; +} + +treecontrol.tree-dark li.tree-normal i { + padding: 1px 10px; + width: 16px; height: 16px; + background: none no-repeat; +} + +treecontrol.tree-dark li .tree-selected { + font-weight: bold; +} + +treecontrol.tree-dark { + color: #ddd; +} \ No newline at end of file diff --git a/demo/tree-controll.html b/demo/tree-controll.html new file mode 100644 index 0000000..0ae7dc0 --- /dev/null +++ b/demo/tree-controll.html @@ -0,0 +1,82 @@ + + + + + + + + + + +
+
+
+

Classic Tree

+
Selected: {{node1.label?node1.label:"N/A"}}
+ + label: {{node.label}} ({{node.id}}) + +
+
+

Light Tree

+
Selected: {{node2.label?node2.label:"N/A"}}
+ + label: {{node.label}} ({{node.id}}) + +
+
+

Dark Tree

+
Selected: {{node3.label?node2.label:"N/A"}}
+ + label: {{node.label}} ({{node.id}}) + +
+
+

Selection

+ Based on callback (on-selection): {{selected}}
+ Based on binding (selected-node): {{node1.label}}, {{node2.label}}, {{node3.label}} +

Mutate the tree

+ add root
+ add child (to the first root of the tree)
+ +
+ + \ No newline at end of file diff --git a/images/file.png b/images/file.png new file mode 100644 index 0000000..ffd22db Binary files /dev/null and b/images/file.png differ diff --git a/images/folder-closed.png b/images/folder-closed.png new file mode 100644 index 0000000..9c8489c Binary files /dev/null and b/images/folder-closed.png differ diff --git a/images/folder.png b/images/folder.png new file mode 100644 index 0000000..fdad546 Binary files /dev/null and b/images/folder.png differ diff --git a/images/node-closed-2.png b/images/node-closed-2.png new file mode 100644 index 0000000..dd92ffd Binary files /dev/null and b/images/node-closed-2.png differ diff --git a/images/node-closed-light.png b/images/node-closed-light.png new file mode 100644 index 0000000..7fd25bc Binary files /dev/null and b/images/node-closed-light.png differ diff --git a/images/node-closed.png b/images/node-closed.png new file mode 100644 index 0000000..d6d65a1 Binary files /dev/null and b/images/node-closed.png differ diff --git a/images/node-opened-2.png b/images/node-opened-2.png new file mode 100644 index 0000000..09ac4fc Binary files /dev/null and b/images/node-opened-2.png differ diff --git a/images/node-opened-light.png b/images/node-opened-light.png new file mode 100644 index 0000000..47b558d Binary files /dev/null and b/images/node-opened-light.png differ diff --git a/images/node-opened.png b/images/node-opened.png new file mode 100644 index 0000000..5b88e61 Binary files /dev/null and b/images/node-opened.png differ diff --git a/tree-control.js b/tree-control.js new file mode 100644 index 0000000..87c0b54 --- /dev/null +++ b/tree-control.js @@ -0,0 +1,119 @@ +(function ( angular ) { + 'use strict'; + + angular.module( 'treeControl', [] ) + .directive( 'treecontrol', ['$compile', function( $compile ) { + return { + restrict: 'E', + require: "treecontrol", + transclude: true, + scope: { + treeModel: "=", + selectedNode: "=", + onSelection: "&", + nodeChildren: "@" + }, + controller: function( $scope ) { + + $scope.nodeChildren = $scope.nodeChildren || 'children'; + $scope.expandedNodes = {}; + + $scope.headClass = function(node) { + if (node[$scope.nodeChildren].length && !$scope.expandedNodes[this.$id]) + return "tree-collapsed"; + else if (node[$scope.nodeChildren].length && $scope.expandedNodes[this.$id]) + return "tree-expanded"; + else + return "tree-normal" + }; + + $scope.nodeExpanded = function() { + return $scope.expandedNodes[this.$id]; + }; + + $scope.selectNodeHead = function() { + $scope.expandedNodes[this.$id] = !$scope.expandedNodes[this.$id]; + }; + + $scope.selectNodeLabel = function( selectedNode ){ + $scope.selectedScope = this.$id; + $scope.selectedNode = selectedNode; + if ($scope.onSelection) + $scope.onSelection({node: selectedNode}); + }; + + $scope.selectedClass = function() { + return (this.$id == $scope.selectedScope)?"tree-selected":""; + }; + + //tree template + var template = + ''; + + return { + templateRoot: $compile(template), + templateChild: $compile(template) + } + }, + compile: function(element, attrs, childTranscludeFn) { + return function ( scope, element, attrs, treemodelCntr ) { + + function updateNodeOnRootScope(newValue) { + if (angular.isArray(newValue)) { + scope.node = {}; + scope.node[scope.nodeChildren] = newValue; + } + else { + scope.node = newValue; + } + } + scope.$watch("treeModel", updateNodeOnRootScope); + updateNodeOnRootScope(scope.treeModel); + + //Rendering template for a root node + treemodelCntr.templateRoot( scope, function(clone) { + element.html('').append( clone ); + }); + // save the transclude function from compile (which is not bound to a scope as apposed to the one from link) + // we can fix this to work with the link transclude function with angular 1.2.6. as for angular 1.2.0 we need + // to keep using the compile function + scope.$treeTransclude = childTranscludeFn; + } + } + }; + }]) + .directive("treeitem", function() { + return { + restrict: 'E', + require: "^treecontrol", + link: function( scope, element, attrs, treemodelCntr) { + + // Rendering template for the current node + treemodelCntr.templateChild(scope, function(clone) { + element.html('').append(clone); + }); + } + } + }) + .directive("treeTransclude", function() { + return { + link: function(scope, element, attrs, controller) { + scope.$treeTransclude(scope, function(clone) { + element.empty(); + element.append(clone); + }); + } + } + }); +})( angular ); + + + +