draggable tree in AngularUI
by johnwun
HTML
<script src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.js"></script>
<script src="https://raw.github.com/furf/nestedSortable/master/jquery.mjs.nestedSortable.js"></script>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css">
<script src="http://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.2/jquery.ui.touch-punch.min.js"></script>
<div ng-app="app" ng-cloak>
<div ng-controller="TreeController">
<ol ui-nested-sortable="{
listTypes: ['I','A',['1','a']],
doNotClear: true,
placeholder: 'ui-state-highlight',
forcePlaceholderSize: true,
toleranceElement: '> div'
}">
<li ng-repeat="child in data.children" tree>
<div><strong>{{child.title}}</strong></div>
<ol><branch></ol>
</li>
</ol>
</div>
</div>
CSS
[ng-cloak] { display:none; }
body { font:12px helvetica,arial,sans-serif; }
ol {
margin:0;
}
li {
cursor:move;
padding:0;
margin:1px;
background:#eee;
border:1px solid #ddd;
padding:0.25em;
}
JavaScript
angular.module('app', ['directives', 'controllers']);
angular.module('directives', [])
/**
* tree
*/
.directive('tree', ['$compile', function ($compile) {
return {
restrict: 'A',
compile: function (tElement, tAttrs) {
var branch = tElement.find('branch'),
repeatExpr,
childExpr,
childrenExpr;
if (!branch.length) {
throw new Error('tree directive must contain a branch node.');
}
repeatExpr = (branch.attr('branch') || tAttrs.ngRepeat).match(/^(.*) in (?:.*\.)?(.*)$/);
childExpr = repeatExpr[1];
childrenExpr = repeatExpr[2];
tElement.attr('ng-repeat', childExpr + ' in ' + childExpr + '.' + childrenExpr);
return function link (scope, element, attrs) {
scope.$depth = scope.$depth || 0;
scope.$watch(childExpr, function(child) {
var childScope = scope.$new();
childScope[childrenExpr] = child[childrenExpr];
childScope.$depth = scope.$depth + 1;
element.find('branch').replaceWith($compile(tElement.clone())(childScope));
});
};
}
};
}])
/**
* uiNestedSortable
*/
.directive('uiNestedSortable', ['$parse', function($parse) {
'use strict';
var eventTypes = 'Create Start Sort Change BeforeStop Stop Update Receive Remove Over Out Activate Deactivate'.split(' ');
return {
restrict: 'A',
link: function(scope, element, attrs) {
var options = attrs.uiNestedSortable ? $parse(attrs.uiNestedSortable)() : {};
angular.forEach(eventTypes, function(eventType) {
var attr = attrs['uiNestedSortable' + eventType],
callback;
if (attr) {
callback = $parse(attr);
options[eventType.toLowerCase()] = function(event, ui) {
scope.$apply(function() {
ui.hierarchy = element.nestedSortable('toHierarchy', {
...