diff --git a/dragula.js b/dragula.js index 4f732311..b99724e7 100644 --- a/dragula.js +++ b/dragula.js @@ -99,7 +99,7 @@ function dragula (initialContainers, options) { if (ignore) { return; // we only care about honest-to-god left clicks and touch events } - var item = e.target; + var item = e.target.shadowRoot && e.composedPath()[0] || e.target; var context = canStart(item); if (!context) { return; @@ -551,16 +551,32 @@ function getElementBehindPoint (point, x, y) { var state = p.className; var el; p.className += ' gu-hide'; - el = doc.elementFromPoint(x, y); + el = elementFromPoint(x, y); p.className = state; return el; + + // Find the topmost element at point x, y. + // Traverses any shadow root to find the deepest element. + function elementFromPoint(x, y) { + var el = doc.elementFromPoint(x, y); + var maybeElem; + while (el && el.shadowRoot) { + maybeElem = el.shadowRoot.elementFromPoint(x, y); + if (maybeElem) { + el = maybeElem; + } else { + return el; + } + } + return el; + } } function never () { return false; } function always () { return true; } function getRectWidth (rect) { return rect.width || (rect.right - rect.left); } function getRectHeight (rect) { return rect.height || (rect.bottom - rect.top); } -function getParent (el) { return el.parentNode === doc ? null : el.parentNode; } +function getParent (el) { return el.parentNode === doc ? null : (el.parentNode || el.host); } function isInput (el) { return el.tagName === 'INPUT' || el.tagName === 'TEXTAREA' || el.tagName === 'SELECT' || isEditable(el); } function isEditable (el) { if (!el) { return false; } // no parents were editable diff --git a/test/cancel.js b/test/cancel.js index eaa93fde..4918bf29 100644 --- a/test/cancel.js +++ b/test/cancel.js @@ -3,6 +3,23 @@ var test = require('tape'); var dragula = require('..'); +test('with normal DOM', function(t) { + domTests(t, document.body); + t.end(); +}); + +test('with nested shadow DOM', function(t) { + var div = document.createElement('div'); + var div2 = document.createElement('div'); + div.createShadowRoot(); + div2.createShadowRoot(); + div.shadowRoot.appendChild(div2); + document.body.appendChild(div); + + domTests(t, div2.shadowRoot); + t.end(); +}); + test('cancel does not throw when not dragging', function (t) { t.test('a single time', function once (st) { var drake = dragula(); @@ -24,85 +41,88 @@ test('cancel does not throw when not dragging', function (t) { 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(); -}); +function domTests(t, root) { -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'); - } -}); + t.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); + root.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 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'); - } -}); + t.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); + root.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, 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'); - } -}); + t.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); + root.appendChild(div); + root.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'); + } + }); + + t.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); + root.appendChild(div); + root.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'); + } + }); +} diff --git a/test/destroy.js b/test/destroy.js index 1fcf178c..3f56261e 100644 --- a/test/destroy.js +++ b/test/destroy.js @@ -2,6 +2,22 @@ var test = require('tape'); var dragula = require('..'); +test('with normal DOM', function(t) { + domTests(t, document.body); + t.end(); +}); + +test('with nested shadow DOM', function(t) { + var div = document.createElement('div'); + var div2 = document.createElement('div'); + div.createShadowRoot(); + div2.createShadowRoot(); + div.shadowRoot.appendChild(div2); + document.body.appendChild(div); + + domTests(t, div2.shadowRoot); + t.end(); +}); test('destroy does not throw when not dragging, destroyed, or whatever', function (t) { t.test('a single time', function once (st) { @@ -24,80 +40,83 @@ test('destroy does not throw when not dragging, destroyed, or whatever', functio 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(); -}); +function domTests(t, root) { + + t.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); + root.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'); - } -}); + t.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); + root.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'); - } -}); + t.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); + root.appendChild(div); + root.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'); - } -}); + t.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); + root.appendChild(div); + root.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'); + } + }); +} diff --git a/test/drag.js b/test/drag.js index baea9182..ba92309e 100644 --- a/test/drag.js +++ b/test/drag.js @@ -4,253 +4,272 @@ 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: 1 }); - testCase('works for wheel clicks', { which: 1 }); - testCase('works when clicking buttons by default', { which: 1 }, { tag: 'button', passes: true }); - testCase('works when clicking anchors by default', { which: 1 }, { tag: 'a', passes: true }); - testCase('fails for right clicks', { which: 2 }, { passes: false }); - testCase('fails for meta-clicks', { which: 1, metaKey: true }, { passes: false }); - testCase('fails for ctrl-clicks', { which: 1, ctrlKey: true }, { passes: false }); - testCase('fails when clicking containers', { which: 1 }, { containerClick: true, passes: false }); - testCase('fails whenever invalid returns true', { which: 1 }, { passes: false, dragulaOpts: { invalid: always } }); - testCase('fails whenever moves returns false', { which: 1 }, { passes: false, dragulaOpts: { moves: never } }); +test('with normal DOM', function(t) { + domTests(t, document.body); 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: 1 }); - events.raise(item2, 'mousemove', { which: 1 }); - 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) { +test('with nested shadow DOM', 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); + div.createShadowRoot(); + div2.createShadowRoot(); + div.shadowRoot.appendChild(div2); 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: 1 }); - events.raise(item2, 'mousemove', { which: 1 }); - t.plan(8); - t.equal(drake.dragging, true, 'final state is drake is dragging'); + + domTests(t, div2.shadowRoot); 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 = 'the force is with this one'; - 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: 1 }); - events.raise(item2, 'mousemove', { which: 1 }); - 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'); - } -}); +function domTests(t, root) { + t.test('drag event gets emitted when clicking an item', function (t) { + testCase('works for left clicks', { which: 1 }); + testCase('works for wheel clicks', { which: 1 }); + testCase('works when clicking buttons by default', { which: 1 }, { tag: 'button', passes: true }); + testCase('works when clicking anchors by default', { which: 1 }, { tag: 'a', passes: true }); + testCase('fails for right clicks', { which: 2 }, { passes: false }); + testCase('fails for meta-clicks', { which: 1, metaKey: true }, { passes: false }); + testCase('fails for ctrl-clicks', { which: 1, ctrlKey: true }, { passes: false }); + testCase('fails when clicking containers', { which: 1 }, { containerClick: true, passes: false }); + testCase('fails whenever invalid returns true', { which: 1 }, { passes: false, dragulaOpts: { invalid: always } }); + testCase('fails whenever moves returns false', { which: 1 }, { 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); + root.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 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: 1 }); - events.raise(item, 'mousemove', { which: 1 }); - t.equal(item.className, 'gu-transit', 'item has gu-transit class'); - t.end(); -}); + t.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); + root.appendChild(div); + drake.start(item1); + drake.on('dragend', end); + drake.on('cancel', cancel); + drake.on('drag', drag); + events.raise(item2, 'mousedown', { which: 1 }); + events.raise(item2, 'mousemove', { which: 1 }); + 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 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: 1 }); - events.raise(item, 'mousemove', { which: 1 }); - t.equal(document.body.className, 'gu-unselectable', 'body has gu-unselectable class'); - t.end(); -}); + t.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); + root.appendChild(div); + root.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: 1 }); + events.raise(item2, 'mousemove', { which: 1 }); + 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 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 = 'the force is with this one'; - div.appendChild(item); - document.body.appendChild(div); - drake.on('cloned', cloned); - events.raise(item, 'mousedown', { which: 1 }); - events.raise(item, 'mousemove', { which: 1 }); - 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`'); - } -}); + t.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 = 'the force is with this one'; + div.appendChild(item1); + div.appendChild(item2); + root.appendChild(div); + drake.start(item1); + drake.on('cloned', cloned); + drake.on('drag', drag); + events.raise(item2, 'mousedown', { which: 1 }); + events.raise(item2, 'mousemove', { which: 1 }); + 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, 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 + t.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); + root.appendChild(div); + events.raise(item, 'mousedown', { which: 1 }); + events.raise(item, 'mousemove', { which: 1 }); + t.equal(item.className, 'gu-transit', 'item has gu-transit class'); + t.end(); }); - item.innerHTML = 'the force is with this one'; - div.appendChild(item); - document.body.appendChild(div); - drake.on('cloned', cloned); - events.raise(item, 'mousedown', { which: 1 }); - events.raise(item, 'mousemove', { which: 1 }); - 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: 1 }); - events.raise(item, 'mousemove', { which: 1 }); - 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(); -}); + t.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); + root.appendChild(div); + events.raise(item, 'mousedown', { which: 1 }); + events.raise(item, 'mousemove', { which: 1 }); + t.equal(document.body.className, 'gu-unselectable', 'body has gu-unselectable class'); + 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: 1 }); - events.raise(item, 'mousemove', { which: 1 }); - 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(); -}); + t.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 = 'the force is with this one'; + div.appendChild(item); + root.appendChild(div); + drake.on('cloned', cloned); + events.raise(item, 'mousedown', { which: 1 }); + events.raise(item, 'mousemove', { which: 1 }); + 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 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 + t.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 = 'the force is with this one'; + div.appendChild(item); + root.appendChild(div); + drake.on('cloned', cloned); + events.raise(item, 'mousedown', { which: 1 }); + events.raise(item, 'mousemove', { which: 1 }); + t.plan(1); + t.end(); + function cloned (mirror) { + t.equal(mirror.parentNode, mirrorContainer, 'mirrors parent is the configured mirrorContainer'); + } + }); + + t.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); + root.appendChild(div); + events.raise(item, 'mousedown', { which: 1 }); + events.raise(item, 'mousemove', { which: 1 }); + 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(); + }); + + t.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); + root.appendChild(div); + events.raise(item, 'mousedown', { which: 1 }); + events.raise(item, 'mousemove', { which: 1 }); + 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(); + }); + + t.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 = 'the force is with this one'; + div.appendChild(item); + root.appendChild(div); + events.raise(item, 'mousedown', { which: 1 }); + events.raise(item, 'mousemove', { which: 1 }); + events.raise(item, 'mousemove', { which: 1 }); // 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(); }); - item.innerHTML = 'the force is with this one'; - div.appendChild(item); - document.body.appendChild(div); - events.raise(item, 'mousedown', { which: 1 }); - events.raise(item, 'mousemove', { which: 1 }); - events.raise(item, 'mousemove', { which: 1 }); // 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; } + function always () { return true; } + function never () { return false; } +} diff --git a/test/end.js b/test/end.js index bd19805a..173b74b7 100644 --- a/test/end.js +++ b/test/end.js @@ -2,6 +2,22 @@ var test = require('tape'); var dragula = require('..'); +test('with normal DOM', function(t) { + domTests(t, document.body); + t.end(); +}); + +test('with nested shadow DOM', function(t) { + var div = document.createElement('div'); + var div2 = document.createElement('div'); + div.createShadowRoot(); + div2.createShadowRoot(); + div.shadowRoot.appendChild(div2); + document.body.appendChild(div); + + domTests(t, div2.shadowRoot); + t.end(); +}); test('end does not throw when not dragging', function (t) { t.test('a single time', function once (st) { @@ -24,54 +40,56 @@ test('end does not throw when not dragging', function (t) { 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'); - } -}); +function domTests(t, root) { + t.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); + root.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'); - } -}); + t.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); + root.appendChild(div); + root.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'); + } + }); +} diff --git a/test/events.js b/test/events.js index 23125d30..d32fdd22 100644 --- a/test/events.js +++ b/test/events.js @@ -4,260 +4,280 @@ 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.equal(copy.nodeType, item.nodeType, '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); +test('with normal DOM', function(t) { + domTests(t, document.body); 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('cancel', cancel); - events.raise(item, 'mousedown', { which: 1 }); - events.raise(item, 'mousemove', { which: 1 }); - drake.end(); - t.plan(3); - t.end(); - function dragend (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) { +test('with nested shadow DOM', 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); + div.createShadowRoot(); + div2.createShadowRoot(); + div.shadowRoot.appendChild(div2); document.body.appendChild(div); - document.body.appendChild(div2); - drake.on('dragend', dragend); - drake.on('drop', drop); - events.raise(item, 'mousedown', { which: 1 }); - events.raise(item, 'mousemove', { which: 1 }); - div2.appendChild(item); - drake.end(); - t.plan(4); - t.end(); - function dragend (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('remove', remove); - events.raise(item, 'mousedown', { which: 1 }); - events.raise(item, 'mousemove', { which: 1 }); - drake.remove(); - t.plan(3); + domTests(t, div2.shadowRoot); t.end(); - function dragend (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('cancel', cancel); - events.raise(item, 'mousedown', { which: 1 }); - events.raise(item, 'mousemove', { which: 1 }); - drake.remove(); - t.plan(4); - t.end(); - function dragend () { - t.pass('dragend got invoked'); - } - function cancel (copy, container) { - t.notEqual(copy, item, 'copy is not a reference to item'); - t.equal(copy.nodeType, item.nodeType, 'item is a copy of item'); - t.equal(container, null, 'container matches expectation'); - } -}); +function domTests(t, root) { + t.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); + root.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.equal(copy.nodeType, item.nodeType, 'copy of original is provided'); + t.equal(original, item, 'original item is provided'); + } + } + }); -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('cancel', cancel); - events.raise(item, 'mousedown', { which: 1 }); - events.raise(item, 'mousemove', { which: 1 }); - drake.cancel(); - t.plan(3); - t.end(); - function dragend (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'); - } -}); + t.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); + root.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('.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('drop', drop); - events.raise(item, 'mousedown', { which: 1 }); - events.raise(item, 'mousemove', { which: 1 }); - 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 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'); - } -}); + t.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); + root.appendChild(div); + drake.on('dragend', dragend); + drake.on('cancel', cancel); + events.raise(item, 'mousedown', { which: 1 }); + events.raise(item, 'mousemove', { which: 1 }); + drake.end(); + t.plan(3); + t.end(); + function dragend (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 "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('cancel', cancel); - events.raise(item, 'mousedown', { which: 1 }); - events.raise(item, 'mousemove', { which: 1 }); - div2.appendChild(item); - drake.cancel(); - t.plan(3); - t.end(); - function dragend (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'); - } -}); + t.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); + root.appendChild(div); + root.appendChild(div2); + drake.on('dragend', dragend); + drake.on('drop', drop); + events.raise(item, 'mousedown', { which: 1 }); + events.raise(item, 'mousemove', { which: 1 }); + div2.appendChild(item); + drake.end(); + t.plan(4); + t.end(); + function dragend (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('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: 1 }); - events.raise(item, 'mousemove', { which: 1 }); - 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.equal(copy.nodeType, item.nodeType, 'mirror of original is provided'); - t.equal(original, item, 'original item is provided'); + t.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); + root.appendChild(div); + drake.on('dragend', dragend); + drake.on('remove', remove); + events.raise(item, 'mousedown', { which: 1 }); + events.raise(item, 'mousemove', { which: 1 }); + drake.remove(); + t.plan(3); + t.end(); + function dragend (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('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: 1 }); - events.raise(item, 'mousemove', { which: 1 }); - t.plan(3); - t.end(); - function cloned (copy, original, type) { - if (type === 'copy') { + t.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); + root.appendChild(div); + drake.on('dragend', dragend); + drake.on('cancel', cancel); + events.raise(item, 'mousedown', { which: 1 }); + events.raise(item, 'mousemove', { which: 1 }); + drake.remove(); + t.plan(4); + t.end(); + function dragend () { + t.pass('dragend got invoked'); + } + function cancel (copy, container) { t.notEqual(copy, item, 'copy is not a reference to item'); - t.equal(copy.nodeType, item.nodeType, 'copy of original is provided'); - t.equal(original, item, 'original item is provided'); + t.equal(copy.nodeType, item.nodeType, 'item is a copy of item'); + t.equal(container, undefined, 'container matches expectation'); } - } -}); + }); -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: 1 }); - events.raise(item, 'mousemove', { which: 1 }); - 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'); - } -}); + t.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); + root.appendChild(div); + drake.on('dragend', dragend); + drake.on('cancel', cancel); + events.raise(item, 'mousedown', { which: 1 }); + events.raise(item, 'mousemove', { which: 1 }); + drake.cancel(); + t.plan(3); + t.end(); + function dragend (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'); + } + }); + + t.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); + root.appendChild(div); + root.appendChild(div2); + drake.on('dragend', dragend); + drake.on('drop', drop); + events.raise(item, 'mousedown', { which: 1 }); + events.raise(item, 'mousemove', { which: 1 }); + 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 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'); + } + }); + + t.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); + root.appendChild(div); + root.appendChild(div2); + drake.on('dragend', dragend); + drake.on('cancel', cancel); + events.raise(item, 'mousedown', { which: 1 }); + events.raise(item, 'mousemove', { which: 1 }); + div2.appendChild(item); + drake.cancel(); + t.plan(3); + t.end(); + function dragend (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'); + } + }); + + t.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); + root.appendChild(div); + drake.on('cloned', cloned); + events.raise(item, 'mousedown', { which: 1 }); + events.raise(item, 'mousemove', { which: 1 }); + 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.equal(copy.nodeType, item.nodeType, 'mirror of original is provided'); + t.equal(original, item, 'original item is provided'); + } + } + }); + + t.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); + root.appendChild(div); + drake.on('cloned', cloned); + events.raise(item, 'mousedown', { which: 1 }); + events.raise(item, 'mousemove', { which: 1 }); + 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.equal(copy.nodeType, item.nodeType, 'copy of original is provided'); + t.equal(original, item, 'original item is provided'); + } + } + }); + + t.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); + root.appendChild(div); + drake.on('drag', drag); + events.raise(item, 'mousedown', { which: 1 }); + events.raise(item, 'mousemove', { which: 1 }); + 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'); + } + }); + +} diff --git a/test/remove.js b/test/remove.js index 035cdf53..597430c6 100644 --- a/test/remove.js +++ b/test/remove.js @@ -4,6 +4,23 @@ var test = require('tape'); var events = require('./lib/events'); var dragula = require('..'); +test('with normal DOM', function(t) { + domTests(t, document.body); + t.end(); +}); + +test('with nested shadow DOM', function(t) { + var div = document.createElement('div'); + var div2 = document.createElement('div'); + div.createShadowRoot(); + div2.createShadowRoot(); + div.shadowRoot.appendChild(div2); + document.body.appendChild(div); + + domTests(t, div2.shadowRoot); + t.end(); +}); + test('remove does not throw when not dragging', function (t) { t.test('a single time', function once (st) { var drake = dragula(); @@ -25,59 +42,62 @@ test('remove does not throw when not dragging', function (t) { 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(); -}); +function domTests(t, root) { -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'); - } -}); + t.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); + root.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 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: 1 }); - events.raise(item, 'mousemove', { which: 1 }); - 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'); - } -}); + t.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); + root.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'); + } + }); + + t.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); + root.appendChild(div); + events.raise(item, 'mousedown', { which: 1 }); + events.raise(item, 'mousemove', { which: 1 }); + 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, undefined, 'cancel was invoked with container'); + } + }); +}