Skip to content

Commit

Permalink
feat(sortable): Closes codef0rmer#59, codef0rmer#92, codef0rmer#155. …
Browse files Browse the repository at this point in the history
…Enable sorting with insertInline with ngAnimate
  • Loading branch information
codef0rmerz committed Sep 6, 2015
1 parent 824fe35 commit ce3bbb5
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 11 deletions.
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@
Implementing jQueryUI Drag and Drop functionality in AngularJS is easier than ever which is a wrapper for jQueryUI draggable/droppable components.


###v1.0.9 - breaking change
1. Draggable and Droppable will not be [deep copied](https://egghead.io/lessons/angularjs-angular-copy-for-deep-copy) by default unlike previous versions. Use `deepCopy` option if prototypical inheritance is not required.
2. Callbacks will not be executed forcefully within the context of scope which requires an extra digest loop for each event (start, stop, over, out, etc), especially drag that fires many times and running a digest loop is performance intensive in such scenario. Call `scope.$apply()` within callback, if needed.


##How to Use

* `bower install angular-dragdrop` (or `sudo bower install angular-dragdrop --allow-root`)
Expand Down Expand Up @@ -44,6 +39,8 @@ Implementing jQueryUI Drag and Drop functionality in AngularJS is easier than ev
* **containment** – string - position/offset. Offset by default. This forces to use jQuery.position() or jQuery.offset() to calculate proper position with respect to parent element or document respectively.
* **deepCopy** - boolean (optional) – If true, makes a deep copy of draggable that looses prototypical inheritance.
* **beforeDrop** – promise (optional) – Ask for confirmation before swapping. Works with both window.confirm and custom popup.
* **insertInline** – boolean(optional) – Make a list sortable. Same model is mandatory for draggable and droppable.
* **direction** – string(optional) – Property name that will be created on each scope to manage animation direction.
* **data-drag** – boolean – If true, element can be draggable. Disabled otherwise.
* **data-jqyoui-options** – object – should hold all the valid options supported by [jQueryUI Draggable](http://api.jqueryui.com/draggable)
* **ng-model** – string – An angular model defined in a controller. Should be a JS array or object
Expand Down Expand Up @@ -76,6 +73,11 @@ Implementing jQueryUI Drag and Drop functionality in AngularJS is easier than ev
Demo is [here](http://codef0rmer.github.io/angular-dragdrop/#/)


###v1.0.9 - breaking change
1. Draggable and Droppable will not be [deep copied](https://egghead.io/lessons/angularjs-angular-copy-for-deep-copy) by default unlike previous versions. Use `deepCopy` option if prototypical inheritance is not required.
2. Callbacks will not be executed forcefully within the context of scope which requires an extra digest loop for each event (start, stop, over, out, etc), especially drag that fires many times and running a digest loop is performance intensive in such scenario. Call `scope.$apply()` within callback, if needed.


###v1.0.5 - breaking change
Do not pass evaluated expressions in callbacks. For example,
####Before:
Expand Down
3 changes: 2 additions & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
},
"devDependencies": {
"angular-mocks": "latest",
"angular-ui-bootstrap-bower": "latest"
"angular-ui-bootstrap-bower": "latest",
"angular-animate": "latest"
}
}
91 changes: 91 additions & 0 deletions demo/dnd-insertInline.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<!DOCTYPE html>
<html ng-app="drag-and-drop">
<head lang="en">
<meta charset="utf-8">
<title>Drag &amp; Drop: Guess A Name</title>
<!-- <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"></script>
<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1/themes/base/jquery-ui.css" rel="stylesheet" type="text/css" />
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.1.1/css/bootstrap.min.css" rel="stylesheet"> -->
<script src="../components/jquery/dist/jquery.min.js"></script>
<script src="../components/jquery-ui/jquery-ui.min.js"></script>
<script src="../components/angular/angular.min.js"></script>
<script src="../components/angular-animate/angular-animate.js"></script>
<script src="../src/angular-dragdrop.js"></script>
<link href="assets/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
padding: 30px;
}
.thumbnails[jqyoui-droppable], .thumbnail[jqyoui-droppable] { border: 1px solid red; }
.thumbnail {
height: 50px;
width: 50px;
text-align: center;
padding-top: 0px;
cursor: pointer;
background: rgb(182, 173, 123);
position: relative;
-webkit-transition: none;
transition: none;
}

.thumbnail[data-drag="false"] { background: green; }

.thumbnail.ng-leave {
-webkit-transition-duration: 0s;
transition-duration: 0s;
opacity: 1;
}

.thumbnail.ng-leave.ng-leave-active {
opacity: 0;
}

.thumbnail.ng-enter {
-webkit-transition: left 0.3s;
transition: left 0.3s;
}
.thumbnail.ng-enter[data-direction="left"] {
left: -80px;
}
.thumbnail.ng-enter[data-direction="right"] {
left: 80px;
}
.thumbnail.ng-enter.ng-enter-active {
left: 0px;
}
</style>

<script type="text/javascript">
var App = angular.module('drag-and-drop', ['ngAnimate', 'ngDragDrop']);

App.controller('oneCtrl', function($scope) {
$scope.list1 = [
{ 'title': 'N', 'drag': true },
{ 'title': 'L', 'drag': true },
{ 'title': 'I', 'drag': true },
{ 'title': 'I', 'drag': true },
{ 'title': 'E', 'drag': true },
{ 'title': 'N', 'drag': true }
];
});
</script>
</head>
<body>
<div ng-controller="oneCtrl">
<div class='contentWrapper ng-cloak'>
<div class='content'>
<div class="row-fluid">
<ul class="thumbnails">
<li class="thumbnail" ng-repeat="item in list1" data-drop="true" data-drag="true" ng-model="list1" jqyoui-droppable="{index: {{$index}}}" jqyoui-draggable="{index: {{$index}}, insertInline: true, direction:'jqyouiDirection'}" data-jqyoui-options="{revert: 'invalid'}" data-direction="{{item.jqyouiDirection}}">
<h1>{{item.title}}</h1>
</li>
</ul>
</div>
</div>
</div>
</div>
</body>
</html>
34 changes: 29 additions & 5 deletions src/angular-dragdrop.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ var jqyoui = angular.module('ngDragDrop', []).service('ngDragDropService', ['$ti
droppableScope = this.droppableScope,
draggableScope = this.draggableScope,
$helper = null,
promises = [];
promises = [],
temp;

dragModel = $draggable.ngattr('ng-model');
dropModel = $droppable.ngattr('ng-model');
Expand Down Expand Up @@ -117,7 +118,26 @@ var jqyoui = angular.module('ngDragDrop', []).service('ngDragDropService', ['$ti
}

$q.all(promises).then(angular.bind(this, function() {
if (dragSettings.animate === true) {
if (dragSettings.insertInline && dragModel === dropModel) {
if (dragSettings.index > dropSettings.index) {
temp = dragModelValue[dragSettings.index];
for (var i = dragSettings.index; i > dropSettings.index; i--) {
dropModelValue[i] = angular.copy(dropModelValue[i - 1]);
dropModelValue[i - 1] = {};
dropModelValue[i][dragSettings.direction] = 'left';
}
dropModelValue[dropSettings.index] = temp;
} else {
temp = dragModelValue[dragSettings.index];
for (var i = dragSettings.index; i < dropSettings.index; i++) {
dropModelValue[i] = angular.copy(dropModelValue[i + 1]);
dropModelValue[i + 1] = {};
dropModelValue[i][dragSettings.direction] = 'right';
}
dropModelValue[dropSettings.index] = temp;
}
this.callEventCallback(droppableScope, dropSettings.onDrop, event, ui);
} else if (dragSettings.animate === true) {
// be nice with absolutely positioned brethren :-)
$helper = $draggable.clone();
$helper.css({'position': 'absolute'}).css($draggable.offset());
Expand Down Expand Up @@ -145,9 +165,9 @@ var jqyoui = angular.module('ngDragDrop', []).service('ngDragDropService', ['$ti
this.callEventCallback(droppableScope, dropSettings.onDrop, event, ui);
}));
}
}), function() {
ui.draggable.css({left: '', top: ''});
});
})).finally(angular.bind(this, function() {
this.restore($draggable);
}));
};

this.move = function($fromEl, $toEl, toPos, duration, dropSettings, callback) {
Expand Down Expand Up @@ -250,6 +270,10 @@ var jqyoui = angular.module('ngDragDrop', []).service('ngDragDropService', ['$ti
}
}

this.restore($draggable);
};

this.restore = function($draggable) {
$draggable.css({'z-index': '', 'left': '', 'top': ''});
};

Expand Down
21 changes: 21 additions & 0 deletions test/spec/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,25 @@ describe('Service: ngDragDropService', function() {
scope.list = {title: 'Item 1'};
expect(ngDragDropService.fixIndex(scope, {applyFilter: 'filterIt'}, scope.list)).toBe(undefined);
});

it('should support insertInline option', function() {
scope.list = [
{ 'title': 'N' },
{ 'title': 'L' },
{ 'title': 'I' },
{ 'title': 'I' },
{ 'title': 'E' },
{ 'title': 'N' }
];
ngDragDropService.draggableScope = ngDragDropService.droppableScope = scope;
expect(scope.list.map(function(item) { return item.title; }).join('')).toBe('NLIIEN');
ngDragDropService.invokeDrop(
$('<div data-drop="true" data-drag="true" ng-model="list" jqyoui-droppable="{index: 5}" jqyoui-draggable="{index: 5, insertInline: true, direction:\'jqyouiDirection\'}">' + scope.list[5].title + '</div>').data('$scope', scope),
$('<div data-drop="true" data-drag="true" ng-model="list" jqyoui-droppable="{index: 0}" jqyoui-draggable="{index: 0, insertInline: true, direction:\'jqyouiDirection\'}">' + scope.list[0].title + '</div>').data('$scope', scope),
document.createEvent('Event'),
{}
);
timeout.flush();
expect(scope.list.map(function(item) { return item.title; }).join('')).toBe('NNLIIE');
});
});

0 comments on commit ce3bbb5

Please sign in to comment.