Drag-and-drop sortable repeater

by Freewind

HTML

<script src="http://code.angularjs.org/1.0.0rc9/angular-1.0.0rc9.min.js"></script>
<script src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<div ng-app="myApp" ng-controller="MasterCtrl">
  <ul>
    <li ng-repeat="i in items" data-index="{{$index}}" sortable="sort(order)">{{i}}</li>
  </ul>
    
  <div ng-repeat="i in items" class="info">
    {{$index}} - {{i}}
  </div>
</div>

CSS

ul,.info {
  margin: 1em;    
}

li {
 padding: 5px;
 background: #EEE;
 margin: 2px;    
}

.sortable-placeholder {
  height: 20px;
  border: 1px dashed black;
}

JavaScript

var myApp = angular.module('myApp', []);

function MasterCtrl($scope) {
  $scope.items = ['orange','apple','kiwi'];
    
  $scope.sort = function(order) {
    var sorted_array = [];
    for(var i=0; i<order.length; i++)
      sorted_array[i] = $scope.items[order[i]];
    
    $scope.items = sorted_array;
  }
}

myApp.directive('sortable', function($log) {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      if (scope.$position === "last") {
        element.ready(function() {
          var ul = element.parent();
          $(ul).sortable('destroy');
      
          $(ul).sortable().bind('sortupdate', function(e, ui) {
              
            var order = $.map($(this).find('li'), function(el) {
               return $(el).attr('data-index'); 
            });
              
            scope.$apply(function() {
               scope.$eval(attrs.sortable, {'order': order});
            });
          });
        });
      }
    }
  }
});
    
    
/* HTML5 Sortable (http://farhadi.ir/projects/html5sortable)
 * Released under the MIT license.
 */(function(a){var b,c=a();a.fn.sortable=function(d){return d=d||{},this.each(function(){if(/^enable|disable|destroy$/.test(d)){var e=a(this).children(a(this).data("items")).attr("draggable",d=="enable");d=="destroy"&&e.add(this).removeData("connectWith").removeData("items").unbind("dragstart.h5s dragend.h5s selectstart.h5s dragover.h5s dragenter.h5s drop.h5s");return}var f,e=a(this).children(d.items),g=d.connectWith||!1,h=a("<"+e[0].tagName+' class="sortable-placeholder">'),i=d.handle,j;e.find(i).mousedown(function(){j=!0}).mouseup(function(){j=!1}),a(this).data("items",d.items),c=c.add(h),g&&a(g).add(this).data("connectWith",g),e.attr("draggable","true").bind("dragstart.h5s",function(c){if(i&&!j)return!1;j=!1;var...