Drag and Drop

by dunerunner

HTML

<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.no-icons.min.css">
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css">
<script src="http://cdnjs.cloudflare.com/ajax/libs/hammer.js/1.0.5/hammer.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<script src="http://s.cdpn.io/61329/angular-hammer.js"></script>
<script src="http://s.cdpn.io/61329/zest.js"></script>
<div class="container" ng-app="dragndropdemo">
<div class="row" ng-controller="dragndropdemo">
  <ul id="names" class="span-3">
	  <li class="input-wrap transition" cu-repeat-reorder='name in names' cu-reorder-handle="i.icon-reorder">
          <i class="icon-reorder"></i>
      <span class="player" type='text'
        tabindex='{{$index + 1}}'
          ng-class="{'last-player': $index == names.length-1}">{{name.val}}</span>
      
    </li>
    <!--<div class="input-wrap">
      <input class="temp-player" type='text'
        ng-model='tempplayer'
        ng-change='updateNames()'
        tabindex='{{names.length + 1}}'
        placeholder='Enter a name...'/>
    </div>-->
 </ul>
    {{names}},{{tempplayer}}
</div>
</div>

CSS

ul {
    list-style-type:none;
}
$player-input-border: 1px solid #ccc

.span-3
  width: 277px
.input-wrap-header
  border: $player-input-border
  border-top-radius: 4px
  border-bottom-radius: 0
  width: 208px !important

.input-wrap, .input-wrap-header
  float: left
  clear: left
  width: 240px
.input-wrap
  i.icon-reorder //to provide a bigger target we pad then reverse with -ve margins
    padding: 6px
    margin: -6px
    margin-left: -26px
    margin-top: -5px
    color: #757575
  
  input
    margin-bottom: 0
    border-radius: 0
    border: $player-input-border
    border-top: none
    padding-right: 20px
  &:first-child input
    border-top: $player-input-border
    border-top-radius: 4px
  &:last-child input
    border-bottom-radius: 4px
  &.dragging input
    border: $player-input-border
  &.dragging-after input
    background-color: green
    border-top: $player-input-border
  &.dragging-before input
    background-color: red
[cu-reorder-handle]
  z-index: 10
  position: relative
	
.dragging[cu-reorder-handle]
  z-index: 11
.active-drag-below
  -moz-user-select: none
  -khtml-user-select: none
  -webkit-user-select: none
  user-select: none

JavaScript

/*
  A LOT of this code comes from the angular.js project

  additionally this uses zest for dom selection and hammer.js (with an angular-hammer wrapper) for touch and mouse-drag event support
*/


    'use strict';
var HashQueueMap, dragndropdemo, hashKey, isArray, module, nextUid, uid;

module = angular.module('dragndropdemo', ['hmTouchEvents']);

dragndropdemo = (function () {
    function dragndropdemo($scope, $timeout) {
        $scope.names = [{
            val: 'bob'
        }, {
            val: 'lucy'
        }, {
            val: 'john'
        }, {
            val: 'luke'
        }, {
            val: 'han'
        }];
    }
    return dragndropdemo;
})();

this.dragndropdemo = dragndropdemo;

module.directive('cuReorderHandle', function () {
    return {
        transclude: false,
        priority: 999,
        terminal: false,
        compile: function (element, attr, linker) {
            var dragElement;
            dragElement = angular.element(zest(attr.cuReorderHandle, element[0])[0]);
            if (dragElement != null) {
                dragElement.attr("hm-drag", "reorderFuncs.moveevent($event, $elementRef, $index)");
                dragElement.attr("hm-dragstart", "reorderFuncs.startevent($event, $elementRef, $index)");
                return dragElement.attr("hm-dragend", "reorderFuncs.stopevent($event, $elementRef, $index)");
            }
        }
    };
});

module.directive('cuRepeatReorder', function () {
    return {
        transclude: "element",
        priority: 1000,
        terminal: true,
        compile: function (element, attr, linker) {
            return function (scope, iterStartElement, attr) {
                var expression, keyIdent, lastOrder, lhs, match, ngRepeatWatch, reorderFuncs, rhs, valueIdent;
                expression = attr.cuRepeatReorder;
                match = expression.match(/^\s*(.+)\s+in\s+(.*)\s*$/);
                lhs = void 0;
                rhs = void 0;
                valueIdent = void 0;
  ...