Skip to content

Commit

Permalink
- removed dependency on jQuery
Browse files Browse the repository at this point in the history
- inject $window and $document instead of creating local vars for them
- prevent duplicate drop events when element has both ng-drag and ng-drop behavior
- don't move the drag element in the initial press, wait till dragging starts
- don't clobber margin of drag element when moving it
  • Loading branch information
sh3rndon committed Dec 22, 2014
1 parent 31c1b8d commit f973841
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 78 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ Drag and drop module for Angular JS with support for touch devices. [`demo`](htt
### Usage:

- Install: `bower install ngDraggable`
- Add `jquery`, `angular` and `ngDraggable` to your code:
- Add `angular` and `ngDraggable` to your code:

```html
<script src='//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js'></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="ngDraggable.js"></script>
```
Expand Down
1 change: 0 additions & 1 deletion example-cancel.html
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ <h2>Cancel drag from child element.</h2>
</div>
<footer style="margin-top:2000px;">footer</footer>

<script src='//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js'></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="ngDraggable.js"></script>
<script>
Expand Down
10 changes: 0 additions & 10 deletions example-clone.html
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,7 @@ <h1>ngDraggable Clone Example</h1>
</div>

</div>



<hr>



</div>


Expand All @@ -116,10 +110,6 @@ <h1>ngDraggable Clone Example</h1>

<footer style="margin-top:2000px;">footer</footer>




<script src='//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js'></script>
<script src='//ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js'></script>
<script src="ngDraggable.js"></script>
<script>
Expand Down
2 changes: 0 additions & 2 deletions example-reorder.html
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,6 @@ <h1>ngDraggable Ordering Example</h1>

<hr/>


<script src='//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js'></script>
<script src='//ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js'></script>
<script src="ngDraggable.js"></script>
<script>
Expand Down
1 change: 0 additions & 1 deletion example.html
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ <h1>ngDraggable Example</h1>
</div>
<footer style="margin-top:2000px;">footer</footer>

<script src='//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js'></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="ngDraggable.js"></script>
<script>
Expand Down
158 changes: 96 additions & 62 deletions ngDraggable.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,19 @@
* https://github.com/fatlinesofcode/ngDraggable
*/
angular.module("ngDraggable", [])
.directive('ngDrag', ['$rootScope', '$parse', function ($rootScope, $parse) {
.directive('ngDrag', ['$rootScope', '$parse', '$document', '$window', function ($rootScope, $parse, $document, $window) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.value = attrs.ngDrag;
// return;
var offset,_centerAnchor=false,_mx,_my,_tx,_ty,_mrx,_mry;
var _hasTouch = ('ontouchstart' in document.documentElement);
var _pressEvents = 'touchstart mousedown';
var _moveEvents = 'touchmove mousemove';
var _releaseEvents = 'touchend mouseup';

var $document = $(document);
var $window = $(window);
// to identify the element in order to prevent getting superflous events when a single element has both drag and drop directives on it.
var _myid = scope.$id;
var _data = null;

var _dragEnabled = false;
Expand All @@ -29,17 +28,26 @@ angular.module("ngDraggable", [])
element.attr('draggable', 'false'); // prevent native drag
toggleListeners(true);
};

// this same func is in ngDrop, it needs to be DRYed up but don't know if its
// worth writing a service (or equivalent) for one function
var _privoffset = function (docElem) {
var box = { top: 0, left: 0 };
if (typeof docElem[0].getBoundingClientRect !== undefined) {
box = docElem[0].getBoundingClientRect();
}
return {
top: box.top + $window.pageYOffset - docElem[0].clientTop,
left: box.left + $window.pageXOffset - docElem[0].clientLeft
};
}

var toggleListeners = function (enable) {
// remove listeners

if (!enable)return;
// add listeners.

scope.$on('$destroy', onDestroy);
//attrs.$observe("ngDrag", onEnableChange);
scope.$watch(attrs.ngDrag, onEnableChange);
//attrs.$observe('ngCenterAnchor', onCenterAnchor);
scope.$on('$destroy', onDestroy);
scope.$watch(attrs.ngDrag, onEnableChange);
scope.$watch(attrs.ngCenterAnchor, onCenterAnchor);
scope.$watch(attrs.ngDragData, onDragDataChange);
element.on(_pressEvents, onpress);
Expand All @@ -63,9 +71,9 @@ angular.module("ngDraggable", [])

var isClickableElement = function (evt) {
return (
angular.isDefined($(evt.target).attr("ng-click"))
|| angular.isDefined($(evt.target).attr("ng-dblclick"))
|| angular.isDefined($(evt.target).attr("ng-cancel-drag"))
angular.isDefined(angular.element(evt.target).attr("ng-click"))
|| angular.isDefined(angular.element(evt.target).attr("ng-dblclick"))
|| angular.isDefined(angular.element(evt.target).attr("ng-cancel-drag"))
);
}
/*
Expand Down Expand Up @@ -101,90 +109,99 @@ angular.module("ngDraggable", [])
var onlongpress = function(evt) {
if(! _dragEnabled)return;
evt.preventDefault();
offset = element.offset();
element.centerX = (element.width()/2);
element.centerY = (element.height()/2);
element.addClass('dragging');
_mx = (evt.pageX || evt.originalEvent.touches[0].pageX);
_my = (evt.pageY || evt.originalEvent.touches[0].pageY);
offset = _privoffset(element);

element.centerX = element[0].offsetWidth / 2;
element.centerY = element[0].offsetHeight / 2;

_mx = (evt.pageX || evt.touches[0].pageX);
_my = (evt.pageY || evt.touches[0].pageY);
_mrx = _mx - offset.left;
_mry = _my - offset.top;

if (_centerAnchor) {
_tx = _mx - element.centerX - $window.scrollLeft();
_ty = _my - element.centerY - $window.scrollTop();
if (_centerAnchor) {
_tx = _mx - element.centerX - $window.pageXOffset;
_ty = _my - element.centerY - $window.pageYOffset;
} else {
_tx = offset.left - $window.scrollLeft();
_ty = offset.top - $window.scrollTop();
}
_tx = _mx - _mrx - $window.pageXOffset;
_ty = _my - _mry - $window.pageYOffset;
}

moveElement(_tx, _ty);
$document.on(_moveEvents, onmove);
$document.on(_releaseEvents, onrelease);
$rootScope.$broadcast('draggable:start', {x:_mx, y:_my, tx:_tx, ty:_ty, event:evt, element:element, data:_data});

}
var onmove = function(evt) {
if(! _dragEnabled)return;

var onmove = function (evt) {
if (!_dragEnabled)return;
evt.preventDefault();

_mx = (evt.pageX || evt.originalEvent.touches[0].pageX);
_my = (evt.pageY || evt.originalEvent.touches[0].pageY);
_mx = (evt.pageX || evt.touches[0].pageX);
_my = (evt.pageY || evt.touches[0].pageY);

if (_centerAnchor) {
_tx = _mx - element.centerX - $window.scrollLeft();
_ty = _my - element.centerY - $window.scrollTop();
_tx = _mx - element.centerX - $window.pageXOffset;
_ty = _my - element.centerY - $window.pageYOffset;
} else {
_tx = _mx - _mrx - $window.scrollLeft();
_ty = _my - _mry - $window.scrollTop();
_tx = _mx - _mrx - $window.pageXOffset;
_ty = _my - _mry - $window.pageYOffset;
}

moveElement(_tx, _ty);

$rootScope.$broadcast('draggable:move', {x:_mx, y:_my, tx:_tx, ty:_ty, event:evt, element:element, data:_data});

$rootScope.$broadcast('draggable:move', { x: _mx, y: _my, tx: _tx, ty: _ty, event: evt, element: element, data: _data, uid: _myid });
}

var onrelease = function(evt) {
if(! _dragEnabled)return;
if (!_dragEnabled)
return;
evt.preventDefault();
$rootScope.$broadcast('draggable:end', {x:_mx, y:_my, tx:_tx, ty:_ty, event:evt, element:element, data:_data, callback:onDragComplete});
$rootScope.$broadcast('draggable:end', {x:_mx, y:_my, tx:_tx, ty:_ty, event:evt, element:element, data:_data, callback:onDragComplete, uid: _myid});
element.removeClass('dragging');
reset();
$document.off(_moveEvents, onmove);
$document.off(_releaseEvents, onrelease);

}

var onDragComplete = function(evt) {
if(! onDragSuccessCallback)return;
if (!onDragSuccessCallback )return;

scope.$apply(function () {
onDragSuccessCallback(scope, {$data: _data, $event: evt});
});
}

var reset = function() {
element.css({left:'',top:'', position:'', 'z-index':'', margin: ''});
}
var moveElement = function(x,y) {
element.css({left:x,top:y, position:'fixed', 'z-index':99999, margin: '0'});

var moveElement = function (x, y) {
element.css({
left: (x+'px'), top: (y+'px'), position: 'fixed', 'z-index': 99999
//,margin: '0' don't monkey with the margin,
});
}
initialize();
}
}
}])
.directive('ngDrop', ['$parse', '$timeout', function ($parse, $timeout) {

.directive('ngDrop', ['$parse', '$timeout', '$window', function ($parse, $timeout, $window) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.value = attrs.ngDrop;

var _myid = scope.$id;

var _dropEnabled=false;

var onDropCallback = $parse(attrs.ngDropSuccess);// || function(){};

var initialize = function () {
toggleListeners(true);
};


var toggleListeners = function (enable) {
// remove listeners

Expand All @@ -197,6 +214,20 @@ angular.module("ngDraggable", [])
scope.$on('draggable:move', onDragMove);
scope.$on('draggable:end', onDragEnd);
};

// this same func is in ngDrag, it needs to be DRYed up but don't know if its
// worth writing a service (or equivalent) for one function
var _privoffset = function (docElem) {
var box = { top: 0, left: 0 };
if (typeof docElem[0].getBoundingClientRect !== undefined) {
box = docElem[0].getBoundingClientRect();
}
return {
top: box.top + $window.pageYOffset - docElem[0].clientTop,
left: box.left + $window.pageXOffset - docElem[0].clientLeft
};
}

var onDestroy = function (enable) {
toggleListeners(false);
};
Expand All @@ -211,31 +242,30 @@ angular.module("ngDraggable", [])
if(! _dropEnabled)return;
isTouching(obj.x,obj.y,obj.element);
}
var onDragEnd = function(evt, obj) {
if(! _dropEnabled)return;
if(isTouching(obj.x,obj.y,obj.element)){

var onDragEnd = function (evt, obj) {

// don't listen to drop events if this is the element being dragged
if (!_dropEnabled || _myid === obj.uid)return;
if (isTouching(obj.x, obj.y, obj.element)) {
// call the ngDraggable ngDragSuccess element callback
if(obj.callback){
obj.callback(obj);
}

// call the ngDrop element callback
// scope.$apply(function () {
// onDropCallback(scope, {$data: obj.data, $event: evt});
// });
$timeout(function(){
onDropCallback(scope, {$data: obj.data, $event: obj});
});


}
updateDragStyles(false, obj.element);
}

var isTouching = function(mouseX, mouseY, dragElement) {
var touching= hitTest(mouseX, mouseY);
updateDragStyles(touching, dragElement);
return touching;
}

var updateDragStyles = function(touching, dragElement) {
if(touching){
element.addClass('drag-enter');
Expand All @@ -245,11 +275,12 @@ angular.module("ngDraggable", [])
dragElement.removeClass('drag-over');
}
}

var hitTest = function(x, y) {
var bounds = element.offset();
bounds.right = bounds.left + element.outerWidth();
bounds.bottom = bounds.top + element.outerHeight();
return x >= bounds.left
var bounds = _privoffset(element);
bounds.right = bounds.left + element[0].offsetWidth;
bounds.bottom = bounds.top + element[0].offsetHeight;
return x >= bounds.left
&& x <= bounds.right
&& y <= bounds.bottom
&& y >= bounds.top;
Expand All @@ -267,7 +298,7 @@ angular.module("ngDraggable", [])
scope.clonedData = {};
var initialize = function () {

img = $(element.find('img'));
img = element.find('img');
element.attr('draggable', 'false');
img.attr('draggable', 'false');
reset();
Expand Down Expand Up @@ -301,8 +332,8 @@ angular.module("ngDraggable", [])
scope.$apply(function () {
scope.clonedData = obj.data;
});
element.css('width', obj.element.width());
element.css('height', obj.element.height());
element.css('width', obj.element[0].offsetWidth);
element.css('height', obj.element[0].offsetHeight);

moveElement(obj.tx, obj.ty);
}
Expand All @@ -323,7 +354,10 @@ angular.module("ngDraggable", [])
element.css({left:0,top:0, position:'fixed', 'z-index':-1, visibility:'hidden'});
}
var moveElement = function(x,y) {
element.css({left:x,top:y, position:'fixed', 'z-index':99999, visibility:'visible'});
element.css({
left: (x+'px'), top: (y+'px'), position: 'fixed', 'z-index': 99999, 'visibility': 'visible'
//,margin: '0' don't monkey with the margin,
});
}

var absorbEvent_ = function (event) {
Expand Down

0 comments on commit f973841

Please sign in to comment.