diff --git a/README.md b/README.md
index dbc97a2..c1eadae 100644
--- a/README.md
+++ b/README.md
@@ -78,6 +78,23 @@ $scope.shinyThings = function (item) {
};
```
+### btf-eliminate
+Makes it so that the item is eliminated if it is not dropped inside of another dragon.
+Add the `btf-eliminate` attribute to an element to get the behavior.
+
+Example:
+```html
+
These get copied
+
+ {{item.name}}
+
+These get moved or eliminated
+
+ {{item.name}}
+
+```
+
+
## Example
See [`example.html`](http://htmlpreview.github.io/?https://github.com/btford/angular-dragon-drop/blob/master/example.html).
diff --git a/dragon-drop.js b/dragon-drop.js
index 3222953..283ad69 100644
--- a/dragon-drop.js
+++ b/dragon-drop.js
@@ -1,13 +1,15 @@
+'use strict';
+
/*
* angular-dragon-drop v0.3.1
* (c) 2013 Brian Ford http://briantford.com
* License: MIT
*/
-'use strict';
+
angular.module('btford.dragon-drop', []).
- directive('btfDragon', function ($document, $compile, $rootScope) {
+ directive('btfDragon', ['$document', '$compile', '$rootScope', function ($document, $compile, $rootScope) {
/*
^ ^
|\ \ / /|
@@ -15,10 +17,10 @@ angular.module('btford.dragon-drop', []).
/ /\ \ \ _ \/ _ / / \
/ / /\ \ {*}\/{*} / / \ \
| | | \ \( (00) ) / // |\ \
- | | | |\ \(V""V)\ / / | || \|
- | | | | \ |^--^| \ / / || || ||
+ | | | |\ \(V""V)\ / / | || \|
+ | | | | \ |^--^| \ / / || || ||
/ / / | |( WWWW__ \/ /| || || ||
- | | | | | | \______\ / / || || ||
+ | | | | | | \______\ / / || || ||
| | | / | | )|______\ ) | / | || ||
/ / / / / /______/ /| \ \ || ||
/ / / / / /\_____/ |/ /__\ \ \ \ \
@@ -32,7 +34,7 @@ angular.module('btford.dragon-drop', []).
\ \________\_ _\ ____/
__/ /\_____ __/ / )\_, _____/
/ ___/ \uuuu/ ___/___) \______/
- VVV V VVV V
+ VVV V VVV V
*/
// this ASCII dragon is really important, do not remove
@@ -40,9 +42,24 @@ angular.module('btford.dragon-drop', []).
dragKey,
dragOrigin,
dragDuplicate = false,
+ dragEliminate = false,
+ mouseReleased = true,
floaty,
offsetX,
- offsetY;
+ offsetY,
+ fixed;
+
+ var isFixed = function(element) {
+ var parents = element.parent(), i, len = parents.length;
+ for (i = 0; i < len; i++) {
+ if (parents[i].hasAttribute('btf-dragon-fixed')) {
+ return true;
+ } else if (parents[i].hasAttribute('btf-dragon')) {
+ return false;
+ }
+ }
+ return false;
+ };
var drag = function (ev) {
var x = ev.clientX - offsetX,
@@ -62,14 +79,32 @@ angular.module('btford.dragon-drop', []).
}
};
- var add = function (collection, item, key) {
+ var add = function (collection, item, key, position) {
if (collection instanceof Array) {
- collection.push(item);
+ var pos;
+ if (position === 0 || position) {
+ pos = position;
+ } else {
+ pos = collection.length;
+ }
+ collection.splice(pos, 0, item);
} else {
collection[key] = item;
}
};
+ var findContainer = function(elem){
+ var children = elem.find('*');
+
+ for (var i = 0; i < children.length; i++){
+ if (children[i].hasAttribute('btf-dragon-container')) {
+ return angular.element(children[i]);
+ }
+ }
+
+ return null;
+ };
+
var documentBody = angular.element($document[0].body);
var disableSelect = function () {
@@ -94,7 +129,9 @@ angular.module('btford.dragon-drop', []).
var killFloaty = function () {
if (floaty) {
+ $rootScope.$broadcast('drag-end');
$document.unbind('mousemove', drag);
+ floaty.scope().$destroy();
floaty.remove();
floaty = null;
}
@@ -103,7 +140,8 @@ angular.module('btford.dragon-drop', []).
var getElementOffset = function (elt) {
var box = elt.getBoundingClientRect();
- var body = $document[0].body;
+ //var body = $document[0].body;
+ var body = $document[0].documentElement;
var xPosition = box.left + body.scrollLeft;
var yPosition = box.top + body.scrollTop;
@@ -127,6 +165,8 @@ angular.module('btford.dragon-drop', []).
};
$document.bind('mouseup', function (ev) {
+ mouseReleased = true;
+
if (!dragValue) {
return;
}
@@ -143,6 +183,43 @@ angular.module('btford.dragon-drop', []).
dropArea = dropArea.parent();
}
+ if (dropArea.attr('btf-dragon-sortable') !== undefined) {
+
+ var min = dropArea[0].getBoundingClientRect().top;
+ var max = dropArea[0].getBoundingClientRect().bottom;
+ var positions = [];
+ var position;
+
+ positions.push(min);
+
+ var i, j, leni, lenj;
+ for (i = 0, leni = dropArea[0].children.length; i < leni; i++) {
+ var totalHeight = 0;
+ var smallestTop = Number.POSITIVE_INFINITY;
+ for (j = 0, lenj = dropArea[0].children[i].getClientRects().length; j < lenj; j++) {
+ if (smallestTop > dropArea[0].children[i].getClientRects()[j].top) {
+ smallestTop = dropArea[0].children[i].getClientRects()[j].top;
+ }
+ totalHeight += dropArea[0].children[i].getClientRects()[j].height;
+ }
+ if (dropArea[0].children[i].attributes['btf-dragon-position'] !== undefined) {
+ positions.push(smallestTop + (totalHeight / 2));
+ }
+
+ }
+
+ positions.push(max);
+
+ i = 0;
+ while (i < positions.length) {
+ if (positions[i] <= ev.clientY) {
+ position = i;
+ }
+ i++;
+ }
+
+ }
+
if (dropArea.length > 0) {
var expression = dropArea.attr('btf-dragon');
var targetScope = dropArea.scope();
@@ -150,9 +227,9 @@ angular.module('btford.dragon-drop', []).
var targetList = targetScope.$eval(match[2]);
targetScope.$apply(function () {
- add(targetList, dragValue, dragKey);
+ add(targetList, dragValue, dragKey, position);
});
- } else if (!dragDuplicate) {
+ } else if (!dragDuplicate && !dragEliminate) {
// no dropArea here
// put item back to origin
$rootScope.$apply(function () {
@@ -173,8 +250,8 @@ angular.module('btford.dragon-drop', []).
var expression = attr.btfDragon;
var match = expression.match(/^\s*(.+)\s+in\s+(.*?)\s*$/);
if (!match) {
- throw Error("Expected btfDragon in form of '_item_ in _collection_' but got '" +
- expression + "'.");
+ throw new Error('Expected btfDragon in form of "_item_ in _collection_" but got "' +
+ expression + '"."');
}
var lhs = match[1];
var rhs = match[2];
@@ -184,8 +261,18 @@ angular.module('btford.dragon-drop', []).
var valueIdentifier = match[3] || match[1];
var keyIdentifier = match[2];
+ var duplicate = container.attr('btf-double-dragon') !== undefined;
+
// pull out the template to re-use.
// Improvised ng-transclude.
+ if (container.attr('btf-dragon-base') !== undefined){
+ container = findContainer(container);
+
+ if (!container){
+ throw new Error('Expected btf-dragon-base to be used with a companion btf-dragon-conatiner');
+ }
+ }
+
var template = container.html();
// wrap text nodes
@@ -201,22 +288,29 @@ angular.module('btford.dragon-drop', []).
var child = template.clone();
child.attr('ng-repeat', expression);
+ if (container.attr('btf-dragon-sortable') !== undefined) {
+ child.attr('btf-dragon-position', '{{$index}}');
+ }
+
container.html('');
container.append(child);
- var duplicate = container.attr('btf-double-dragon') !== undefined;
+ var eliminate = container.attr('btf-dragon-eliminate') !== undefined;
+
return function (scope, elt, attr) {
var accepts = scope.$eval(attr.btfDragonAccepts);
if (accepts !== undefined && typeof accepts !== 'function') {
- throw Error('Expected btfDragonAccepts to be a function.');
+ throw new Error('Expected btfDragonAccepts to be a function.');
}
var spawnFloaty = function () {
+ $rootScope.$broadcast('drag-start');
scope.$apply(function () {
floaty = template.clone();
+
floaty.css('position', 'fixed');
floaty.css('margin', '0px');
@@ -235,10 +329,38 @@ angular.module('btford.dragon-drop', []).
};
elt.bind('mousedown', function (ev) {
- if (dragValue) {
+
+ //If a person uses middle or right mouse button, don't do anything
+ if ([1, 2].indexOf(ev.button) > -1) {
+ return;
+ }
+
+ var tag = $document[0].elementFromPoint(ev.clientX,ev.clientY).tagName;
+ if (tag === 'SELECT' || tag === 'INPUT' || tag === 'BUTTON') {
+ return;
+ } else {
+
+ mouseReleased = false;
+
+ if (isFixed(angular.element(ev.target))) {
+ fixed = true;
+ } else {
+ fixed = false;
+ }
+
+ }
+
+ });
+
+ elt.bind('mousemove', function(ev) {
+ if(dragValue||mouseReleased){
+ return;
+ }
+
+ if(isFixed(angular.element(ev.target)) || fixed){
return;
}
-
+
// find the right parent
var originElement = angular.element(ev.target);
var originScope = originElement.scope();
@@ -268,14 +390,17 @@ angular.module('btford.dragon-drop', []).
});
}
dragDuplicate = duplicate;
+ dragEliminate = eliminate;
+
offsetX = (ev.pageX - offset.left);
offsetY = (ev.pageY - offset.top);
spawnFloaty();
drag(ev);
+
});
};
}
};
- });
+ }]);