Skip to content

Commit

Permalink
new API endpoints and manual drag start
Browse files Browse the repository at this point in the history
  • Loading branch information
bevacqua committed Apr 17, 2015
1 parent 228e8b2 commit 7d414d5
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 34 deletions.
7 changes: 7 additions & 0 deletions changelog.markdown
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# 1.4.0 Top Fuel

- Added a `dragend` event that's always fired
- Added a `dragging` property to API
- Introduced manual `start` API method
- Introduced `addContainer` and `removeContainer` dynamic API

# 1.3.0 Terror

Introduced an `.end` instance API method that gracefully ends the drag event using the last known valid drop target.
Expand Down
83 changes: 56 additions & 27 deletions dragula.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ var body = document.body;
var documentElement = document.documentElement;

function dragula (containers, options) {
var _dragging; // are we dragging something?
var _mirror; // mirror image
var _source; // source container
var _item; // item being dragged
Expand All @@ -25,24 +24,34 @@ function dragula (containers, options) {
if (o.direction === void 0) { o.direction = 'vertical'; }

var api = emitter({
addContainer: manipulateContainers('add'),
removeContainer: manipulateContainers('remove'),
start: start,
end: end,
cancel: cancel,
remove: remove,
destroy: destroy
destroy: destroy,
dragging: false
});

events();

return api;

function manipulateContainers (op) {
return function addOrRemove (all) {
var containers = Array.isArray(all) ? all : [all];
containers.forEach(track);
function track (container) {
touchy(container, op, 'mousedown', grab);
}
};
}

function events (remove) {
var op = remove ? 'remove' : 'add';
touchy(documentElement, op, 'mouseup', release);
containers.forEach(track);

function track (container) {
touchy(container, op, 'mousedown', grab);
}
api[op + 'Container'](containers);
}

function destroy () {
Expand All @@ -51,14 +60,28 @@ function dragula (containers, options) {
}

function grab (e) {
var item = e.target;

if ((e.which !== 0 && e.which !== 1) || e.metaKey || e.ctrlKey) {
return; // we only care about honest-to-god left clicks and touch events
}
if (_dragging) {
if (start(item) !== true) {
return;
}

var offset = getOffset(_item);
_offsetX = getCoord('pageX', e) - offset.left;
_offsetY = getCoord('pageY', e) - offset.top;
renderMirrorImage();
drag(e);
e.preventDefault();
}

function start (item) {
if (api.dragging && _mirror) {
return;
}

var item = e.target;
if (containers.indexOf(item) !== -1) {
return; // don't drag container itself
}
Expand All @@ -78,9 +101,7 @@ function dragula (containers, options) {
return;
}

var offset = getOffset(item);

e.preventDefault();
end();

if (o.copy) {
_copy = item.cloneNode(true);
Expand All @@ -92,28 +113,27 @@ function dragula (containers, options) {
_source = container;
_item = item;
_initialSibling = _currentSibling = nextEl(item);
_offsetX = getCoord('pageX', e) - offset.left;
_offsetY = getCoord('pageY', e) - offset.top;

api.dragging = true;
api.emit('drag', _item, _source);
renderMirrorImage();
drag(e);

return true;
}

function invalidTarget (el) {
return el.tagName === 'A' || el.tagName === 'BUTTON';
}

function end () {
if (!_dragging) {
if (!api.dragging) {
return;
}
var item = _copy || _item;
drop(item, item.parentElement);
}

function release (e) {
if (!_dragging) {
if (!api.dragging) {
return;
}

Expand Down Expand Up @@ -141,7 +161,7 @@ function dragula (containers, options) {
}

function remove () {
if (!_dragging) {
if (!api.dragging) {
return;
}
var item = _copy || _item;
Expand All @@ -154,7 +174,7 @@ function dragula (containers, options) {
}

function cancel (revert) {
if (!_dragging) {
if (!api.dragging) {
return;
}
var reverts = arguments.length > 0 ? revert : o.revertOnSpill;
Expand All @@ -180,6 +200,8 @@ function dragula (containers, options) {
removeMirrorImage();
rmClass(item, 'gu-transit');
_source = _item = _copy = _initialSibling = _currentSibling = null;
api.dragging = false;
api.emit('dragend', item);
}

function isInitialPlacement (target, s) {
Expand Down Expand Up @@ -211,6 +233,10 @@ function dragula (containers, options) {
}

function drag (e) {
if (!_mirror) {
return;
}

var clientX = getCoord('clientX', e);
var clientY = getCoord('clientY', e);
var x = clientX - _offsetX;
Expand Down Expand Up @@ -238,8 +264,10 @@ function dragula (containers, options) {
}

function renderMirrorImage () {
if (_mirror) {
return;
}
var rect = _item.getBoundingClientRect();
_dragging = true;
_mirror = _item.cloneNode(true);
_mirror.style.width = rect.width + 'px';
_mirror.style.height = rect.height + 'px';
Expand All @@ -256,7 +284,6 @@ function dragula (containers, options) {
touchy(documentElement, 'remove', 'mousemove', drag);
_mirror.parentElement.removeChild(_mirror);
_mirror = null;
_dragging = false;
}
}

Expand Down Expand Up @@ -340,14 +367,16 @@ function getScroll (scrollProp, offsetProp) {
return body[scrollProp];
}

function getElementBehindPoint (behind, x, y) {
function getElementBehindPoint (point, x, y) {
if (!x && !y) {
return null;
}
var state = behind.className;
behind.className += ' gu-hide';
var el = document.elementFromPoint(x, y);
behind.className = state;
var p = point || {};
var state = p.className;
var el;
p.className += ' gu-hide';
el = document.elementFromPoint(x, y);
p.className = state;
return el;
}

Expand Down
31 changes: 24 additions & 7 deletions readme.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,12 @@ Also note that **the position where a drag starts is always going to be a valid

If `copy` is set to `true`, items will be copied rather than moved. This implies the following differences:

Event | Move | Copy
---------|------------------------------------------|---------------------------------------------
`drag` | Element will be concealed from `source` | Nothing happens
`drop` | Element will be moved into `target` | Element will be cloned into `target`
`remove` | Element will be removed from DOM | Nothing happens
`cancel` | Element will stay in `source` | Nothing happens
Event | Move | Copy
----------|------------------------------------------|---------------------------------------------
`drag` | Element will be concealed from `source` | Nothing happens
`drop` | Element will be moved into `target` | Element will be cloned into `target`
`remove` | Element will be removed from DOM | Nothing happens
`cancel` | Element will stay in `source` | Nothing happens

#### `options.revertOnSpill`

Expand All @@ -106,6 +106,22 @@ When an element is dropped onto a container, it'll be placed near the point wher

The `dragula` method returns a tiny object with a concise API. We'll refer to the API returned by `dragula` as `drake`.

#### `drake.addContainer(container)`

Adds a `container` to the `containers` collection. It can be a single DOM element or an array.

#### `drake.removeContainer(container)`

Removes a `container` from the `containers` collection. It can be a single DOM element or an array.

#### `drake.dragging`

This property will be `true` whenever an element is being dragged.

#### `drake.start(item)`

Enter drag mode **without a shadow**. This method is most useful when providing complementary keyboard shortcuts to an existing drag and drop solution. Even though a shadow won't be created at first, the user will get one as soon as they click on `item` and start dragging it around. Note that if they click and drag something else, `.end` will be called before picking up the new item.

#### `drake.end()`

Gracefully end the drag event as if using **the last position marked by the preview shadow** as the drop target. The proper `cancel` or `drop` event will be fired, depending on whether the item was dropped back where it was originally lifted from _(which is essentially a no-op that's treated as a `cancel` event)_.
Expand All @@ -130,10 +146,11 @@ The `drake` is an event emitter. The following events can be tracked using `drak
Event Name | Listener Arguments | Event Description
-----------|-------------------------|-------------------------------------------------------------------------------------
`drag` | `el, container` | `el` was lifted from `container`
`dragend` | `el` | Dragging event for `el` ended with either `cancel`, `remove`, or `drop`
`drop` | `el, container, source` | `el` was dropped into `container`, and originally came from `source`
`cancel` | `el, container` | `el` was being dragged but it got nowhere and went back into `container`, it's last stable parent
`remove` | `el, container` | `el` was being dragged but it got nowhere and it was removed from the DOM. It's last stable parent was `container`.
`shadow` | `el, container` | `el`, _the visual aid shadow_, was moved into `container`. May trigger many times as the position of `el` changes, even within the same `container`
`shadow` | `el, container` | `el`, _the visual aid shadow_, was moved into `container`. May trigger many times as the position of `el` changes, even within the same `container`

#### `drake.destroy()`

Expand Down

0 comments on commit 7d414d5

Please sign in to comment.