Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 77 additions & 61 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,34 +16,45 @@ var _vue2 = _interopRequireDefault(_vue);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var _data = {
draggableElementId: null, // if this is present, only a specific area of the draggable will respond to dragging (eg header bar).
down: false,
height: 0,
width: 0,
initialX: 0,
initialY: 0,
constraintToWindow: false,
cursorPreviousX: 0,
cursorPreviousY: 0,
draggerOffsetLeft: 0,
draggerOffsetTop: 0,
overlay: null,
draggableEl: null,
initialZIndex: undefined
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var VdragData = function VdragData() {
_classCallCheck(this, VdragData);

this.down = false;
this.draggableElementId = null; // if this is present, only a specific area of the draggable will respond to dragging (eg header bar). down = false;
this.height = 0;
this.width = 0;
this.initialX = 0;
this.initialY = 0;
this.constraintToWindow = false;
this.cursorPreviousX = 0;
this.cursorPreviousY = 0;
this.draggerOffsetLeft = 0;
this.draggerOffsetTop = 0;
this.overlay = null;
this.draggableEl = null;
this.initialZIndex = undefined;
};

function createOverlay(e, el, _data) {
;

function createOverlay(e, el) {
var overlay = document.createElement('div');

if (!el.vdrag_data) {
el.vdrag_data = new VdragData();
}

overlay.setAttribute('style', '\n width: 100vw; \n height: 100vh; \n position: absolute;\n top: 0;\n left: 0;\n z-index: 10000;\n ');
overlay.addEventListener('mouseup', function (e) {
return mouseup(e, el, _data);
return mouseup(e, el);
});
overlay.addEventListener('mousedown', function (e) {
return mousedown(e, el, _data);
return mousedown(e, el);
});
overlay.addEventListener('mousemove', function (e) {
return mousemove(e, el, _data);
return mousemove(e, el);
});
document.body.appendChild(overlay);

Expand All @@ -63,44 +74,44 @@ function adjustElementZIndex(el, index) {
el.style.zIndex = index;
}

function mousedown(e, el, _data) {
function mousedown(e, el) {
// if the user set a argument to v-drag,
// it means they only want a specific area to be draggable
// eg: `v-drag:drag-header` means only the element with
// id="drag-header" should be draggable.
// If the user clicked another area, do nothing.
if (_data.draggableElementId && !checkIfIdInPath(_data.draggableElementId, e.path)) {
if (el.vdrag_data.draggableElementId && !checkIfIdInPath(el.vdrag_data.draggableElementId, e.path)) {
return;
}

if (_data.overlay) {
_data.overlay.remove();
if (el.vdrag_data.overlay) {
el.vdrag_data.overlay.remove();
}
// set the width each click
// just in case it changed since last time (by external plugin, for example)
_data.width = el.offsetWidth;
_data.height = el.offsetHeight;
_data.down = true;
_data.initialX = e.clientX;
_data.initialY = e.clientY;
var overlay = createOverlay(e, el, _data);
_data.overlay = overlay;
el.vdrag_data.width = el.offsetWidth;
el.vdrag_data.height = el.offsetHeight;
el.vdrag_data.down = true;
el.vdrag_data.initialX = e.clientX;
el.vdrag_data.initialY = e.clientY;
var overlay = createOverlay(e, el, el.vdrag_data);
el.vdrag_data.overlay = overlay;
adjustElementZIndex(el, 10001);
}

function mouseup(e, el, _data) {
_data.down = false;
if (!_data.overlay) {
function mouseup(e, el) {
el.vdrag_data.down = false;
if (!el.vdrag_data.overlay) {
return;
}

_data.overlay.removeEventListener('mouseup', mouseup);
_data.overlay.removeEventListener('mousedown', mousedown);
_data.overlay.removeEventListener('mousemove', mousemove);
_data.overlay.remove();
adjustElementZIndex(el, _data.initialZIndex);
el.vdrag_data.overlay.removeEventListener('mouseup', mouseup);
el.vdrag_data.overlay.removeEventListener('mousedown', mousedown);
el.vdrag_data.overlay.removeEventListener('mousemove', mousemove);
el.vdrag_data.overlay.remove();
adjustElementZIndex(el, el.vdrag_data.initialZIndex);

setDraggerOffset(el, _data);
setDraggerOffset(el);
}

function reachedLeft(el, _data, movingLeft) {
Expand All @@ -119,47 +130,52 @@ function reachedBottom(el, _data, movingDown) {
return el.offsetTop + _data.height >= window.innerHeight && !movingDown;
}

function mousemove(e, el, _data) {
if (_data.down) {
var movingLeft = _data.cursorPreviousX > e.clientX;
var movingRight = _data.cursorPreviousX < e.clientX;
var movingUp = _data.cursorPreviousY < e.clientY;
var movingDown = _data.cursorPreviousY > e.clientY;
function mousemove(e, el) {
if (el.vdrag_data.down) {
var movingLeft = el.vdrag_data.cursorPreviousX > e.clientX;
var movingRight = el.vdrag_data.cursorPreviousX < e.clientX;
var movingUp = el.vdrag_data.cursorPreviousY < e.clientY;
var movingDown = el.vdrag_data.cursorPreviousY > e.clientY;

if (_data.constraintToWindow && (reachedLeft(el, _data, movingLeft) || reachedRight(el, _data, movingRight))) {
if (el.vdrag_data.constraintToWindow && (reachedLeft(el, el.vdrag_data, movingLeft) || reachedRight(el, el.vdrag_data, movingRight))) {
// do now allow moving outside the window horizontally
} else {
el.style.left = _data.draggerOffsetLeft + (e.clientX - _data.initialX) + 'px';
el.style.left = el.vdrag_data.draggerOffsetLeft + (e.clientX - el.vdrag_data.initialX) + 'px';
}
if (_data.constraintToWindow && (reachedTop(el, _data, movingUp) || reachedBottom(el, _data, movingDown))) {
if (el.vdrag_data.constraintToWindow && (reachedTop(el, el.vdrag_data, movingUp) || reachedBottom(el, el.vdrag_data, movingDown))) {
// do now allow moving outside the window vertically
} else {
el.style.top = _data.draggerOffsetTop + (e.clientY - _data.initialY) + 'px';
el.style.top = el.vdrag_data.draggerOffsetTop + (e.clientY - el.vdrag_data.initialY) + 'px';
}
}
_data.cursorPreviousX = e.clientX;
_data.cursorPreviousY = e.clientY;
el.vdrag_data.cursorPreviousX = e.clientX;
el.vdrag_data.cursorPreviousY = e.clientY;
}

function setDraggerOffset(el, _data) {
_data.draggerOffsetLeft = el.offsetLeft;
_data.draggerOffsetTop = el.offsetTop;
function setDraggerOffset(el) {
el.vdrag_data.draggerOffsetLeft = el.offsetLeft;
el.vdrag_data.draggerOffsetTop = el.offsetTop;
}

exports.default = _vue2.default.directive('drag', {
inserted: function inserted(el, binding, vnode) {
_data.draggableElementId = binding.arg || null;
_data.constraintToWindow = binding.modifiers['window-only'];

if (!el.vdrag_data) {
el.vdrag_data = new VdragData();
}

el.vdrag_data.draggableElementId = binding.arg || null;
el.vdrag_data.constraintToWindow = binding.modifiers['window-only'];
el.addEventListener('mouseup', function (e) {
return mouseup(e, el, _data);
return mouseup(e, el);
});
el.addEventListener('mousedown', function (e) {
return mousedown(e, el, _data);
return mousedown(e, el);
});
el.addEventListener('mousemove', function (e) {
return mousemove(e, el, _data);
return mousemove(e, el);
});
setDraggerOffset(el, _data);
_data.initialZIndex = el.style.zIndex;
setDraggerOffset(el);
el.vdrag_data.initialZIndex = el.style.zIndex;
}
});
72 changes: 41 additions & 31 deletions src/__tests__/drag.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,19 @@ describe('drag', () => {
describe('setInitialOffset', () => {
it('sets the initial offset of the element', () => {
const data = {
draggerOffsetLeft: 0,
draggerOffsetTop: 0
}
const el = {
offsetLeft: 1,
offsetTop: 1
offsetTop: 1,
vdrag_data: {
draggerOffsetLeft: 0,
draggerOffsetTop: 0
}
}

setDraggerOffset(el, data)
expect(data.draggerOffsetLeft).toBe(1)
expect(data.draggerOffsetTop).toBe(1)
setDraggerOffset(el)
expect(el.vdrag_data.draggerOffsetLeft).toBe(1)
expect(el.vdrag_data.draggerOffsetTop).toBe(1)
})
})

Expand All @@ -46,33 +48,30 @@ describe('drag', () => {
context("mouse is not down", () => {
it('does not move element but updates cursorPrevious position', () => {
const data = {
down: false,
cursorPreviousX: 0,
cursorPreviousY: 0
}
const el = {
style: {
left: 0,
top: 0
top: 0,
},
vdrag_data: {
down: false,
cursorPreviousX: 0,
cursorPreviousY: 0
}
}

mousemove({ clientX: 1, clientY: 1 }, el, data)
mousemove({ clientX: 1, clientY: 1 }, el)

expect(el.style.left).toBe(0)
expect(el.style.top).toBe(0)
expect(data.cursorPreviousX).toBe(1)
expect(data.cursorPreviousX).toBe(1)
expect(el.vdrag_data.cursorPreviousX).toBe(1)
expect(el.vdrag_data.cursorPreviousX).toBe(1)
})
})

it('updates the element style if down === true', () => {
const data = {
down: true,
initialX: 10,
initialY: 10,
draggerOffsetLeft: 0,
draggerOffsetTop: 0
}
const e = {
clientX: 20, // clientX - initialX. 20 - 10 = 10
Expand All @@ -81,11 +80,18 @@ describe('drag', () => {
const el = {
style: {
left: 0,
top: 0
top: 0,
},
vdrag_data: {
down: true,
initialX: 10,
initialY: 10,
draggerOffsetLeft: 0,
draggerOffsetTop: 0
}
}

mousemove(e, el, data)
mousemove(e, el)
// draggerOffsetLeft (0) + clientX (20) - initialX (10) = 10
expect(el.style.left).toBe('10px')
expect(el.style.top).toBe('10px')
Expand All @@ -95,36 +101,40 @@ describe('drag', () => {
describe('mouseup', () => {
it('sets down = false', () => {
const data = {
}
mockEl.vdrag_data = {
down: true,
overlay: mockEl,
initialZIndex: 0
}

mouseup(undefined, mockEl, data)
expect(data.down).toBe(false)
mouseup(undefined, mockEl)
expect(mockEl.vdrag_data.down).toBe(false)
})
})

describe('mousedown', () => {
it('sets down = true and initial mouse position', () => {
const data = {
initialX: 0,
initialY: 0,
down: false
}
const el = {
parentElement: { append: () => {} },
style: { zIndex: 0 }
style: { zIndex: 0 },
vdrag_data: {
initialX: 0,
initialY: 0,
down: false
}
}
const evt = {
clientX: 1,
clientY: 1
}

mousedown(evt, el, data)
expect(data.down).toBe(true)
expect(data.initialX).toBe(1)
expect(data.initialY).toBe(1)
mousedown(evt, el)
expect(el.vdrag_data.down).toBe(true)
expect(el.vdrag_data.initialX).toBe(1)
expect(el.vdrag_data.initialY).toBe(1)
})
})

Expand All @@ -134,7 +144,7 @@ describe('drag', () => {
const parentEl = document.createElement('div')
parentEl.appendChild(el)

const result = createOverlay(undefined, el, {})
const result = createOverlay(undefined, el)

expect(result.getAttribute('style').includes('width: 100vw')).toBe(true)
expect(result.getAttribute('style').includes('height: 100vh')).toBe(true)
Expand Down
Loading