1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

support drag and drop for playlist items

This commit is contained in:
Luke Pulverenti 2015-10-15 01:48:03 -04:00
parent 80929558e6
commit fd64c014a3
45 changed files with 4202 additions and 3 deletions

View file

@ -0,0 +1,108 @@
'use strict';
var test = require('tape');
var dragula = require('..');
test('cancel does not throw when not dragging', function (t) {
t.test('a single time', function once (st) {
var drake = dragula();
st.doesNotThrow(function () {
drake.cancel();
}, 'dragula ignores a single call to drake.cancel');
st.end();
});
t.test('multiple times', function once (st) {
var drake = dragula();
st.doesNotThrow(function () {
drake.cancel();
drake.cancel();
drake.cancel();
drake.cancel();
}, 'dragula ignores multiple calls to drake.cancel');
st.end();
});
t.end();
});
test('when dragging and cancel gets called, nothing happens', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div]);
div.appendChild(item);
document.body.appendChild(div);
drake.start(item);
drake.cancel();
t.equal(div.children.length, 1, 'nothing happens');
t.equal(drake.dragging, false, 'drake has stopped dragging');
t.end();
});
test('when dragging and cancel gets called, cancel event is emitted', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div]);
div.appendChild(item);
document.body.appendChild(div);
drake.start(item);
drake.on('cancel', cancel);
drake.on('dragend', dragend);
drake.cancel();
t.plan(3);
t.end();
function dragend () {
t.pass('dragend got called');
}
function cancel (target, container) {
t.equal(target, item, 'cancel was invoked with item');
t.equal(container, div, 'cancel was invoked with container');
}
});
test('when dragging a copy and cancel gets called, default does not revert', function (t) {
var div = document.createElement('div');
var div2 = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div, div2]);
div.appendChild(item);
document.body.appendChild(div);
document.body.appendChild(div2);
drake.start(item);
div2.appendChild(item);
drake.on('drop', drop);
drake.on('dragend', dragend);
drake.cancel();
t.plan(4);
t.end();
function dragend () {
t.pass('dragend got called');
}
function drop (target, parent, source) {
t.equal(target, item, 'drop was invoked with item');
t.equal(parent, div2, 'drop was invoked with final container');
t.equal(source, div, 'drop was invoked with source container');
}
});
test('when dragging a copy and cancel gets called, revert is executed', function (t) {
var div = document.createElement('div');
var div2 = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div, div2]);
div.appendChild(item);
document.body.appendChild(div);
document.body.appendChild(div2);
drake.start(item);
div2.appendChild(item);
drake.on('cancel', cancel);
drake.on('dragend', dragend);
drake.cancel(true);
t.plan(3);
t.end();
function dragend () {
t.pass('dragend got called');
}
function cancel (target, container) {
t.equal(target, item, 'cancel was invoked with item');
t.equal(container, div, 'cancel was invoked with container');
}
});

View file

@ -0,0 +1,65 @@
'use strict';
var test = require('tape');
var classes = require('../classes');
test('classes exports the expected api', function (t) {
t.equal(typeof classes.add, 'function', 'classes.add is a method');
t.equal(typeof classes.rm, 'function', 'classes.rm is a method');
t.end();
});
test('classes can add a class', function (t) {
var el = document.createElement('div');
classes.add(el, 'gu-foo');
t.equal(el.className, 'gu-foo', 'setting a class works');
t.end();
});
test('classes can add a class to an element that already has classes', function (t) {
var el = document.createElement('div');
el.className = 'bar';
classes.add(el, 'gu-foo');
t.equal(el.className, 'bar gu-foo', 'appending a class works');
t.end();
});
test('classes.add is a no-op if class already is in element', function (t) {
var el = document.createElement('div');
el.className = 'gu-foo';
classes.add(el, 'gu-foo');
t.equal(el.className, 'gu-foo', 'no-op as expected');
t.end();
});
test('classes can remove a class', function (t) {
var el = document.createElement('div');
el.className = 'gu-foo';
classes.rm(el, 'gu-foo');
t.equal(el.className, '', 'removing a class works');
t.end();
});
test('classes can remove a class from a list on the right', function (t) {
var el = document.createElement('div');
el.className = 'bar gu-foo';
classes.rm(el, 'gu-foo');
t.equal(el.className, 'bar', 'removing a class from the list works to the right');
t.end();
});
test('classes can remove a class from a list on the left', function (t) {
var el = document.createElement('div');
el.className = 'gu-foo bar';
classes.rm(el, 'gu-foo');
t.equal(el.className, 'bar', 'removing a class from the list works to the left');
t.end();
});
test('classes can remove a class from a list on the middle', function (t) {
var el = document.createElement('div');
el.className = 'foo gu-foo bar';
classes.rm(el, 'gu-foo');
t.equal(el.className, 'foo bar', 'removing a class from the list works to the middle');
t.end();
});

View file

@ -0,0 +1,38 @@
'use strict';
var test = require('tape');
var dragula = require('..');
test('drake defaults to no containers', function (t) {
var drake = dragula();
t.ok(Array.isArray(drake.containers), 'drake.containers is an array');
t.equal(drake.containers.length, 0, 'drake.containers is empty');
t.end();
});
test('drake reads containers from array argument', function (t) {
var el = document.createElement('div');
var containers = [el];
var drake = dragula(containers);
t.equal(drake.containers, containers, 'drake.containers matches input');
t.equal(drake.containers.length, 1, 'drake.containers has one item');
t.end();
});
test('drake reads containers from array in options', function (t) {
var el = document.createElement('div');
var containers = [el];
var drake = dragula({ containers: containers });
t.equal(drake.containers, containers, 'drake.containers matches input');
t.equal(drake.containers.length, 1, 'drake.containers has one item');
t.end();
});
test('containers in options take precedent', function (t) {
var el = document.createElement('div');
var containers = [el];
var drake = dragula([], { containers: containers });
t.equal(drake.containers, containers, 'drake.containers matches input');
t.equal(drake.containers.length, 1, 'drake.containers has one item');
t.end();
});

View file

@ -0,0 +1,19 @@
'use strict';
var test = require('tape');
var dragula = require('..');
test('drake has sensible default options', function (t) {
var options = {};
dragula(options);
t.equal(typeof options.moves, 'function', 'options.moves defaults to a method');
t.equal(typeof options.accepts, 'function', 'options.accepts defaults to a method');
t.equal(typeof options.invalid, 'function', 'options.invalid defaults to a method');
t.equal(typeof options.isContainer, 'function', 'options.isContainer defaults to a method');
t.equal(options.copy, false, 'options.copy defaults to false');
t.equal(options.revertOnSpill, false, 'options.revertOnSpill defaults to false');
t.equal(options.removeOnSpill, false, 'options.removeOnSpill defaults to false');
t.equal(options.direction, 'vertical', 'options.direction defaults to \'vertical\'');
t.equal(options.mirrorContainer, document.body, 'options.mirrorContainer defaults to an document.body');
t.end();
});

View file

@ -0,0 +1,103 @@
'use strict';
var test = require('tape');
var dragula = require('..');
test('destroy does not throw when not dragging, destroyed, or whatever', function (t) {
t.test('a single time', function once (st) {
var drake = dragula();
st.doesNotThrow(function () {
drake.destroy();
}, 'dragula bites into a single call to drake.destroy');
st.end();
});
t.test('multiple times', function once (st) {
var drake = dragula();
st.doesNotThrow(function () {
drake.destroy();
drake.destroy();
drake.destroy();
drake.destroy();
}, 'dragula bites into multiple calls to drake.destroy');
st.end();
});
t.end();
});
test('when dragging and destroy gets called, nothing happens', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div]);
div.appendChild(item);
document.body.appendChild(div);
drake.start(item);
drake.destroy();
t.equal(div.children.length, 1, 'nothing happens');
t.equal(drake.dragging, false, 'drake has stopped dragging');
t.end();
});
test('when dragging and destroy gets called, dragend event is emitted gracefully', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div]);
div.appendChild(item);
document.body.appendChild(div);
drake.start(item);
drake.on('dragend', dragend);
drake.destroy();
t.plan(1);
t.end();
function dragend () {
t.pass('dragend got called');
}
});
test('when dragging a copy and destroy gets called, default does not revert', function (t) {
var div = document.createElement('div');
var div2 = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div, div2]);
div.appendChild(item);
document.body.appendChild(div);
document.body.appendChild(div2);
drake.start(item);
div2.appendChild(item);
drake.on('drop', drop);
drake.on('dragend', dragend);
drake.destroy();
t.plan(4);
t.end();
function dragend () {
t.pass('dragend got called');
}
function drop (target, parent, source) {
t.equal(target, item, 'drop was invoked with item');
t.equal(parent, div2, 'drop was invoked with final container');
t.equal(source, div, 'drop was invoked with source container');
}
});
test('when dragging a copy and destroy gets called, revert is executed', function (t) {
var div = document.createElement('div');
var div2 = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div, div2], { revertOnSpill: true });
div.appendChild(item);
document.body.appendChild(div);
document.body.appendChild(div2);
drake.start(item);
div2.appendChild(item);
drake.on('cancel', cancel);
drake.on('dragend', dragend);
drake.destroy();
t.plan(3);
t.end();
function dragend () {
t.pass('dragend got called');
}
function cancel (target, container) {
t.equal(target, item, 'cancel was invoked with item');
t.equal(container, div, 'cancel was invoked with container');
}
});

View file

@ -0,0 +1,256 @@
'use strict';
var test = require('tape');
var events = require('./lib/events');
var dragula = require('..');
test('drag event gets emitted when clicking an item', function (t) {
testCase('works for left clicks', { which: 0 });
testCase('works for wheel clicks', { which: 1 });
testCase('works when clicking buttons by default', { which: 0 }, { tag: 'button', passes: true });
testCase('works when clicking anchors by default', { which: 0 }, { tag: 'a', passes: true });
testCase('fails for right clicks', { which: 2 }, { passes: false });
testCase('fails for meta-clicks', { which: 0, metaKey: true }, { passes: false });
testCase('fails for ctrl-clicks', { which: 0, ctrlKey: true }, { passes: false });
testCase('fails when clicking containers', { which: 0 }, { containerClick: true, passes: false });
testCase('fails whenever invalid returns true', { which: 0 }, { passes: false, dragulaOpts: { invalid: always } });
testCase('fails whenever moves returns false', { which: 0 }, { passes: false, dragulaOpts: { moves: never } });
t.end();
function testCase (desc, eventOptions, options) {
t.test(desc, function subtest (st) {
var o = options || {};
var div = document.createElement('div');
var item = document.createElement(o.tag || 'div');
var passes = o.passes !== false;
var drake = dragula([div], o.dragulaOpts);
div.appendChild(item);
document.body.appendChild(div);
drake.on('drag', drag);
events.raise(o.containerClick ? div : item, 'mousedown', eventOptions);
events.raise(o.containerClick ? div : item, 'mousemove');
st.plan(passes ? 4 : 1);
st.equal(drake.dragging, passes, desc + ': final state is drake is ' + (passes ? '' : 'not ') + 'dragging');
st.end();
function drag (target, container) {
st[passes ? 'pass' : 'fail'](desc + ': drag event was emitted synchronously');
st.equal(target, item, desc + ': first argument is selected item');
st.equal(container, div, desc + ': second argument is container');
}
});
}
});
test('when already dragging, mousedown/mousemove ends (cancels) previous drag', function (t) {
var div = document.createElement('div');
var item1 = document.createElement('div');
var item2 = document.createElement('div');
var drake = dragula([div]);
div.appendChild(item1);
div.appendChild(item2);
document.body.appendChild(div);
drake.start(item1);
drake.on('dragend', end);
drake.on('cancel', cancel);
drake.on('drag', drag);
events.raise(item2, 'mousedown', { which: 0 });
events.raise(item2, 'mousemove', { which: 0 });
t.plan(7);
t.equal(drake.dragging, true, 'final state is drake is dragging');
t.end();
function end (item) {
t.equal(item, item1, 'dragend invoked with correct item');
}
function cancel (item, source) {
t.equal(item, item1, 'cancel invoked with correct item');
t.equal(source, div, 'cancel invoked with correct source');
}
function drag (item, container) {
t.pass('drag event was emitted synchronously');
t.equal(item, item2, 'first argument is selected item');
t.equal(container, div, 'second argument is container');
}
});
test('when already dragged, ends (drops) previous drag', function (t) {
var div = document.createElement('div');
var div2 = document.createElement('div');
var item1 = document.createElement('div');
var item2 = document.createElement('div');
var drake = dragula([div, div2]);
div.appendChild(item1);
div.appendChild(item2);
document.body.appendChild(div);
document.body.appendChild(div2);
drake.start(item1);
div2.appendChild(item1);
drake.on('dragend', end);
drake.on('drop', drop);
drake.on('drag', drag);
events.raise(item2, 'mousedown', { which: 0 });
events.raise(item2, 'mousemove', { which: 0 });
t.plan(8);
t.equal(drake.dragging, true, 'final state is drake is dragging');
t.end();
function end (item) {
t.equal(item, item1, 'dragend invoked with correct item');
}
function drop (item, target, source) {
t.equal(item, item1, 'drop invoked with correct item');
t.equal(source, div, 'drop invoked with correct source');
t.equal(target, div2, 'drop invoked with correct target');
}
function drag (item, container) {
t.pass('drag event was emitted synchronously');
t.equal(item, item2, 'first argument is selected item');
t.equal(container, div, 'second argument is container');
}
});
test('when copying, emits cloned with the copy', function (t) {
var div = document.createElement('div');
var item1 = document.createElement('div');
var item2 = document.createElement('span');
var drake = dragula([div], { copy: true });
item2.innerHTML = '<em>the force is <strong>with this one</strong></em>';
div.appendChild(item1);
div.appendChild(item2);
document.body.appendChild(div);
drake.start(item1);
drake.on('cloned', cloned);
drake.on('drag', drag);
events.raise(item2, 'mousedown', { which: 0 });
events.raise(item2, 'mousemove', { which: 0 });
t.plan(12);
t.equal(drake.dragging, true, 'final state is drake is dragging');
t.end();
function cloned (copy, item) {
t.notEqual(copy, item2, 'first argument is not exactly the target');
t.equal(copy.tagName, item2.tagName, 'first argument has same tag as target');
t.equal(copy.innerHTML, item2.innerHTML, 'first argument has same inner html as target');
t.equal(item, item2, 'second argument is clicked item');
}
function drag (item, container) {
t.pass('drag event was emitted synchronously');
t.equal(item, item2, 'first argument is selected item');
t.equal(container, div, 'second argument is container');
}
});
test('when dragging, element gets gu-transit class', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
dragula([div]);
div.appendChild(item);
document.body.appendChild(div);
events.raise(item, 'mousedown', { which: 0 });
events.raise(item, 'mousemove', { which: 0 });
t.equal(item.className, 'gu-transit', 'item has gu-transit class');
t.end();
});
test('when dragging, body gets gu-unselectable class', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
dragula([div]);
div.appendChild(item);
document.body.appendChild(div);
events.raise(item, 'mousedown', { which: 0 });
events.raise(item, 'mousemove', { which: 0 });
t.equal(document.body.className, 'gu-unselectable', 'body has gu-unselectable class');
t.end();
});
test('when dragging, element gets a mirror image for show', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div]);
item.innerHTML = '<em>the force is <strong>with this one</strong></em>';
div.appendChild(item);
document.body.appendChild(div);
drake.on('cloned', cloned);
events.raise(item, 'mousedown', { which: 0 });
events.raise(item, 'mousemove', { which: 0 });
t.plan(4);
t.end();
function cloned (mirror, target) {
t.equal(item.className, 'gu-transit', 'item does not have gu-mirror class');
t.equal(mirror.className, 'gu-mirror', 'mirror only has gu-mirror class');
t.equal(mirror.innerHTML, item.innerHTML, 'mirror is passed to \'cloned\' event');
t.equal(target, item, 'cloned lets you know that the mirror is a clone of `item`');
}
});
test('when dragging, mirror element gets appended to configured mirrorContainer', function (t) {
var mirrorContainer = document.createElement('div');
var div = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div], {
'mirrorContainer': mirrorContainer
});
item.innerHTML = '<em>the force is <strong>with this one</strong></em>';
div.appendChild(item);
document.body.appendChild(div);
drake.on('cloned', cloned);
events.raise(item, 'mousedown', { which: 0 });
events.raise(item, 'mousemove', { which: 0 });
t.plan(1);
t.end();
function cloned (mirror) {
t.equal(mirror.parentNode, mirrorContainer, 'mirrors parent is the configured mirrorContainer');
}
});
test('when dragging stops, element gets gu-transit class removed', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div]);
div.appendChild(item);
document.body.appendChild(div);
events.raise(item, 'mousedown', { which: 0 });
events.raise(item, 'mousemove', { which: 0 });
t.equal(item.className, 'gu-transit', 'item has gu-transit class');
drake.end();
t.equal(item.className, '', 'item has gu-transit class removed');
t.end();
});
test('when dragging stops, body becomes selectable again', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div]);
div.appendChild(item);
document.body.appendChild(div);
events.raise(item, 'mousedown', { which: 0 });
events.raise(item, 'mousemove', { which: 0 });
t.equal(document.body.className, 'gu-unselectable', 'body has gu-unselectable class');
drake.end();
t.equal(document.body.className, '', 'body got gu-unselectable class removed');
t.end();
});
test('when drag begins, check for copy option', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
item.className = 'copyable';
div.className = 'contains';
var drake = dragula([div], {
copy: checkCondition
});
item.innerHTML = '<em>the force is <strong>with this one</strong></em>';
div.appendChild(item);
document.body.appendChild(div);
events.raise(item, 'mousedown', { which: 0 });
events.raise(item, 'mousemove', { which: 0 });
events.raise(item, 'mousemove', { which: 0 }); // ensure the copy method condition is only asserted once
t.plan(2);
t.end();
function checkCondition (el, source) {
t.equal(el.className, 'copyable', 'dragged element classname is copyable');
t.equal(source.className, 'contains', 'source container classname is contains');
return true;
}
drake.end();
});
function always () { return true; }
function never () { return false; }

View file

@ -0,0 +1,27 @@
'use strict';
var test = require('tape');
var dragula = require('..');
test('drake can be instantiated without throwing', function (t) {
t.doesNotThrow(drakeFactory, 'calling dragula() without arguments does not throw');
t.end();
function drakeFactory () {
return dragula();
}
});
test('drake has expected api properties', function (t) {
var drake = dragula();
t.ok(drake, 'drake is not null');
t.equal(typeof drake, 'object', 'drake is an object');
t.ok(Array.isArray(drake.containers), 'drake.containers is an array');
t.equal(typeof drake.start, 'function', 'drake.start is a method');
t.equal(typeof drake.end, 'function', 'drake.end is a method');
t.equal(typeof drake.cancel, 'function', 'drake.cancel is a method');
t.equal(typeof drake.remove, 'function', 'drake.remove is a method');
t.equal(typeof drake.destroy, 'function', 'drake.destroy is a method');
t.equal(typeof drake.dragging, 'boolean', 'drake.dragging is a boolean');
t.equal(drake.dragging, false, 'drake.dragging is initialized as false');
t.end();
});

View file

@ -0,0 +1,77 @@
'use strict';
var test = require('tape');
var dragula = require('..');
test('end does not throw when not dragging', function (t) {
t.test('a single time', function once (st) {
var drake = dragula();
st.doesNotThrow(function () {
drake.end();
}, 'dragula ignores a single call to drake.end');
st.end();
});
t.test('multiple times', function once (st) {
var drake = dragula();
st.doesNotThrow(function () {
drake.end();
drake.end();
drake.end();
drake.end();
}, 'dragula ignores multiple calls to drake.end');
st.end();
});
t.end();
});
test('when already dragging, .end() ends (cancels) previous drag', function (t) {
var div = document.createElement('div');
var item1 = document.createElement('div');
var item2 = document.createElement('div');
var drake = dragula([div]);
div.appendChild(item1);
div.appendChild(item2);
document.body.appendChild(div);
drake.start(item1);
drake.on('dragend', end);
drake.on('cancel', cancel);
drake.end();
t.plan(4);
t.equal(drake.dragging, false, 'final state is: drake is not dragging');
t.end();
function end (item) {
t.equal(item, item1, 'dragend invoked with correct item');
}
function cancel (item, source) {
t.equal(item, item1, 'cancel invoked with correct item');
t.equal(source, div, 'cancel invoked with correct source');
}
});
test('when already dragged, ends (drops) previous drag', function (t) {
var div = document.createElement('div');
var div2 = document.createElement('div');
var item1 = document.createElement('div');
var item2 = document.createElement('div');
var drake = dragula([div, div2]);
div.appendChild(item1);
div.appendChild(item2);
document.body.appendChild(div);
document.body.appendChild(div2);
drake.start(item1);
div2.appendChild(item1);
drake.on('dragend', end);
drake.on('drop', drop);
drake.end();
t.plan(5);
t.equal(drake.dragging, false, 'final state is: drake is not dragging');
t.end();
function end (item) {
t.equal(item, item1, 'dragend invoked with correct item');
}
function drop (item, target, source) {
t.equal(item, item1, 'drop invoked with correct item');
t.equal(source, div, 'drop invoked with correct source');
t.equal(target, div2, 'drop invoked with correct target');
}
});

View file

@ -0,0 +1,292 @@
'use strict';
var test = require('tape');
var events = require('./lib/events');
var dragula = require('..');
test('.start() emits "cloned" for copies', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div], { copy: true });
div.appendChild(item);
document.body.appendChild(div);
drake.on('cloned', cloned);
drake.start(item);
t.plan(3);
t.end();
function cloned (copy, original, type) {
if (type === 'copy') {
t.notEqual(copy, item, 'copy is not a reference to item');
t.deepEqual(copy, item, 'copy of original is provided');
t.equal(original, item, 'original item is provided');
}
}
});
test('.start() emits "drag" for items', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div]);
div.appendChild(item);
document.body.appendChild(div);
drake.on('drag', drag);
drake.start(item);
t.plan(2);
t.end();
function drag (original, container) {
t.equal(original, item, 'item is a reference to moving target');
t.equal(container, div, 'container matches expected div');
}
});
test('.end() emits "cancel" when not moved', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div]);
div.appendChild(item);
document.body.appendChild(div);
drake.on('dragend', dragend);
drake.on('out', out);
drake.on('cancel', cancel);
events.raise(item, 'mousedown', { which: 0 });
events.raise(item, 'mousemove', { which: 0 });
drake.end();
t.plan(4);
t.end();
function dragend (original) {
t.equal(original, item, 'item is a reference to moving target');
}
function out (original) {
t.equal(original, item, 'item is a reference to moving target');
}
function cancel (original, container) {
t.equal(original, item, 'item is a reference to moving target');
t.equal(container, div, 'container matches expected div');
}
});
test('.end() emits "drop" when moved', function (t) {
var div = document.createElement('div');
var div2 = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div, div2]);
div.appendChild(item);
document.body.appendChild(div);
document.body.appendChild(div2);
drake.on('dragend', dragend);
drake.on('out', out);
drake.on('drop', drop);
events.raise(item, 'mousedown', { which: 0 });
events.raise(item, 'mousemove', { which: 0 });
div2.appendChild(item);
drake.end();
t.plan(5);
t.end();
function dragend (original) {
t.equal(original, item, 'item is a reference to moving target');
}
function out (original) {
t.equal(original, item, 'item is a reference to moving target');
}
function drop (original, target, container) {
t.equal(original, item, 'item is a reference to moving target');
t.equal(target, div2, 'target matches expected div');
t.equal(container, div, 'container matches expected div');
}
});
test('.remove() emits "remove" for items', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div]);
div.appendChild(item);
document.body.appendChild(div);
drake.on('dragend', dragend);
drake.on('out', out);
drake.on('remove', remove);
events.raise(item, 'mousedown', { which: 0 });
events.raise(item, 'mousemove', { which: 0 });
drake.remove();
t.plan(4);
t.end();
function dragend (original) {
t.equal(original, item, 'item is a reference to moving target');
}
function out (original) {
t.equal(original, item, 'item is a reference to moving target');
}
function remove (original, container) {
t.equal(original, item, 'item is a reference to moving target');
t.equal(container, div, 'container matches expected div');
}
});
test('.remove() emits "cancel" for copies', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div], { copy: true });
div.appendChild(item);
document.body.appendChild(div);
drake.on('dragend', dragend);
drake.on('out', out);
drake.on('cancel', cancel);
events.raise(item, 'mousedown', { which: 0 });
events.raise(item, 'mousemove', { which: 0 });
drake.remove();
t.plan(6);
t.end();
function dragend () {
t.pass('dragend got invoked');
}
function out (copy) {
t.notEqual(copy, item, 'copy is not a reference to item');
t.deepEqual(copy, item, 'item is a copy of item');
}
function cancel (copy, container) {
t.notEqual(copy, item, 'copy is not a reference to item');
t.deepEqual(copy, item, 'item is a copy of item');
t.equal(container, null, 'container matches expectation');
}
});
test('.cancel() emits "cancel" when not moved', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div]);
div.appendChild(item);
document.body.appendChild(div);
drake.on('dragend', dragend);
drake.on('out', out);
drake.on('cancel', cancel);
events.raise(item, 'mousedown', { which: 0 });
events.raise(item, 'mousemove', { which: 0 });
drake.cancel();
t.plan(4);
t.end();
function dragend (original) {
t.equal(original, item, 'item is a reference to moving target');
}
function out (original) {
t.equal(original, item, 'item is a reference to moving target');
}
function cancel (original, container) {
t.equal(original, item, 'item is a reference to moving target');
t.equal(container, div, 'container matches expected div');
}
});
test('.cancel() emits "drop" when not reverted', function (t) {
var div = document.createElement('div');
var div2 = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div]);
div.appendChild(item);
document.body.appendChild(div);
document.body.appendChild(div2);
drake.on('dragend', dragend);
drake.on('out', out);
drake.on('drop', drop);
events.raise(item, 'mousedown', { which: 0 });
events.raise(item, 'mousemove', { which: 0 });
div2.appendChild(item);
drake.cancel();
t.plan(5);
t.end();
function dragend (original) {
t.equal(original, item, 'item is a reference to moving target');
}
function out (original) {
t.equal(original, item, 'item is a reference to moving target');
}
function drop (original, parent, container) {
t.equal(original, item, 'item is a reference to moving target');
t.equal(parent, div2, 'parent matches expected div');
t.equal(container, div, 'container matches expected div');
}
});
test('.cancel() emits "cancel" when reverts', function (t) {
var div = document.createElement('div');
var div2 = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div], { revertOnSpill: true });
div.appendChild(item);
document.body.appendChild(div);
document.body.appendChild(div2);
drake.on('dragend', dragend);
drake.on('out', out);
drake.on('cancel', cancel);
events.raise(item, 'mousedown', { which: 0 });
events.raise(item, 'mousemove', { which: 0 });
div2.appendChild(item);
drake.cancel();
t.plan(4);
t.end();
function dragend (original) {
t.equal(original, item, 'item is a reference to moving target');
}
function out (original) {
t.equal(original, item, 'item is a reference to moving target');
}
function cancel (original, container) {
t.equal(original, item, 'item is a reference to moving target');
t.equal(container, div, 'container matches expected div');
}
});
test('mousedown emits "cloned" for mirrors', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div]);
div.appendChild(item);
document.body.appendChild(div);
drake.on('cloned', cloned);
events.raise(item, 'mousedown', { which: 0 });
events.raise(item, 'mousemove', { which: 0 });
t.plan(3);
t.end();
function cloned (copy, original, type) {
if (type === 'mirror') {
t.notEqual(copy, item, 'mirror is not a reference to item');
t.deepEqual(copy, item, 'mirror of original is provided');
t.equal(original, item, 'original item is provided');
}
}
});
test('mousedown emits "cloned" for copies', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div], { copy: true });
div.appendChild(item);
document.body.appendChild(div);
drake.on('cloned', cloned);
events.raise(item, 'mousedown', { which: 0 });
events.raise(item, 'mousemove', { which: 0 });
t.plan(3);
t.end();
function cloned (copy, original, type) {
if (type === 'copy') {
t.notEqual(copy, item, 'copy is not a reference to item');
t.deepEqual(copy, item, 'copy of original is provided');
t.equal(original, item, 'original item is provided');
}
}
});
test('mousedown emits "drag" for items', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div]);
div.appendChild(item);
document.body.appendChild(div);
drake.on('drag', drag);
events.raise(item, 'mousedown', { which: 0 });
events.raise(item, 'mousemove', { which: 0 });
t.plan(2);
t.end();
function drag (original, container) {
t.equal(original, item, 'item is a reference to moving target');
t.equal(container, div, 'container matches expected div');
}
});

View file

@ -0,0 +1,16 @@
'use strict';
function raise (el, type, options) {
var o = options || {};
var e = document.createEvent('Event');
e.initEvent(type, true, true);
Object.keys(o).forEach(apply);
el.dispatchEvent(e);
function apply (key) {
e[key] = o[key];
}
}
module.exports = {
raise: raise
};

View file

@ -0,0 +1,9 @@
'use strict';
var test = require('tape');
var dragula = require('..');
test('public api matches expectation', function (t) {
t.equal(typeof dragula, 'function', 'dragula is a function');
t.end();
});

View file

@ -0,0 +1,106 @@
'use strict';
var test = require('tape');
var events = require('./lib/events');
var dragula = require('..');
test('remove does not throw when not dragging', function (t) {
t.test('a single time', function once (st) {
var drake = dragula();
st.doesNotThrow(function () {
drake.remove();
}, 'dragula ignores a single call to drake.remove');
st.end();
});
t.test('multiple times', function once (st) {
var drake = dragula();
st.doesNotThrow(function () {
drake.remove();
drake.remove();
drake.remove();
drake.remove();
}, 'dragula ignores multiple calls to drake.remove');
st.end();
});
t.end();
});
test('when dragging and remove gets called, element is removed', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div]);
div.appendChild(item);
document.body.appendChild(div);
drake.start(item);
drake.remove();
t.equal(div.children.length, 0, 'item got removed from container');
t.equal(drake.dragging, false, 'drake has stopped dragging');
t.end();
});
test('when dragging and remove gets called, remove event is emitted', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div]);
div.appendChild(item);
document.body.appendChild(div);
drake.start(item);
drake.on('remove', remove);
drake.on('dragend', dragend);
drake.remove();
t.plan(3);
t.end();
function dragend () {
t.pass('dragend got called');
}
function remove (target, container) {
t.equal(target, item, 'remove was invoked with item');
t.equal(container, div, 'remove was invoked with container');
}
});
test('when dragging a copy and remove gets called, cancel event is emitted', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div], { copy: true });
div.appendChild(item);
document.body.appendChild(div);
events.raise(item, 'mousedown', { which: 0 });
events.raise(item, 'mousemove', { which: 0 });
drake.on('cancel', cancel);
drake.on('dragend', dragend);
drake.remove();
t.plan(4);
t.end();
function dragend () {
t.pass('dragend got called');
}
function cancel (target, container) {
t.equal(target.className, 'gu-transit', 'cancel was invoked with item');
t.notEqual(target, item, 'item is a copy and not the original');
t.equal(container, null, 'cancel was invoked with container');
}
});
test('when dragging a copy and remove gets called, cancel event is emitted', function (t) {
var div = document.createElement('div');
var item = document.createElement('div');
var drake = dragula([div], { copy: true });
div.appendChild(item);
document.body.appendChild(div);
events.raise(item, 'mousedown', { which: 0 });
events.raise(item, 'mousemove', { which: 0 });
drake.on('cancel', cancel);
drake.on('dragend', dragend);
drake.remove();
t.plan(4);
t.end();
function dragend () {
t.pass('dragend got called');
}
function cancel (target, container) {
t.equal(target.className, 'gu-transit', 'cancel was invoked with item');
t.notEqual(target, item, 'item is a copy and not the original');
t.equal(container, null, 'cancel was invoked with container');
}
});