mirror of
https://github.com/TracksApp/tracks.git
synced 2025-09-22 05:50:47 +02:00
163 lines
No EOL
6 KiB
JavaScript
163 lines
No EOL
6 KiB
JavaScript
(function($) {
|
|
/*
|
|
* Simulate drag of a JQuery UI sortable list
|
|
* Repository: https://github.com/mattheworiordan/jquery.simulate.drag-sortable.js
|
|
* Author: http://mattheworiordan.com
|
|
*
|
|
* options are:
|
|
* - move: move item up (positive) or down (negative) by Integer amount
|
|
* - handle: selector for the draggable handle element (optional)
|
|
* - listItem: selector to limit which sibling items can be used for reordering
|
|
* - placeHolder: if a placeholder is used during dragging, we need to consider it's height
|
|
*
|
|
*/
|
|
$.fn.simulateDragSortable = function(options) {
|
|
// build main options before element iteration
|
|
var opts = $.extend({}, $.fn.simulateDragSortable.defaults, options);
|
|
|
|
// iterate and move each matched element
|
|
return this.each(function() {
|
|
// allow for a drag handle if item is not draggable
|
|
var that = this,
|
|
handle = opts.handle ? $(this).find(opts.handle)[0] : $(this)[0],
|
|
listItem = opts.listItem,
|
|
placeHolder = opts.placeHolder,
|
|
sibling = $(this),
|
|
moveCounter = Math.floor(opts.move),
|
|
direction = moveCounter > 0 ? 'down' : 'up',
|
|
moveVerticalAmount = 0,
|
|
dragPastBy = 0;
|
|
|
|
if (moveCounter === 0) { return; }
|
|
|
|
while (moveCounter !== 0) {
|
|
if (direction === 'down') {
|
|
if (sibling.next(listItem).length) {
|
|
sibling = sibling.next(listItem);
|
|
moveVerticalAmount += sibling.outerHeight();
|
|
}
|
|
moveCounter -= 1;
|
|
} else {
|
|
if (sibling.prev(listItem).length) {
|
|
sibling = sibling.prev(listItem);
|
|
moveVerticalAmount -= sibling.outerHeight();
|
|
}
|
|
moveCounter += 1;
|
|
}
|
|
}
|
|
|
|
var center = findCenter(handle);
|
|
var x = Math.floor(center.x), y = Math.floor(center.y);
|
|
dispatchEvent(handle, 'mousedown', createEvent('mousedown', handle, { clientX: x, clientY: y }));
|
|
// simulate drag start
|
|
dispatchEvent(document, 'mousemove', createEvent('mousemove', document, { clientX: x+1, clientY: y+1 }));
|
|
|
|
// Sortable is using a fixed height placeholder meaning items jump up and down as you drag variable height items into fixed height placeholder
|
|
placeHolder = placeHolder && $(this).parent().find(placeHolder);
|
|
if (placeHolder && placeHolder.length) {
|
|
// we're going to move past it, and back again
|
|
moveVerticalAmount += (direction === 'down' ? -1 : 1) * Math.min($(this).outerHeight() / 2, 5);
|
|
// Sortable UI bug when dragging down and place holder exists. You need to drag past by the total height of this
|
|
// and then drag back to the right point
|
|
dragPastBy = (direction === 'down' ? 1 : -1) * $(this).outerHeight() / 2;
|
|
} else {
|
|
// no place holder
|
|
if (direction === 'down') {
|
|
// need to move at least as far as this item and or the last sibling
|
|
if ($(this).outerHeight() > $(sibling).outerHeight()) {
|
|
moveVerticalAmount += $(this).outerHeight() - $(sibling).outerHeight();
|
|
}
|
|
moveVerticalAmount += $(sibling).outerHeight() / 2;
|
|
} else {
|
|
// move a little extra to ensure item clips into next position
|
|
moveVerticalAmount -= Math.min($(this).outerHeight() / 2, 5);
|
|
}
|
|
}
|
|
|
|
if (sibling[0] !== $(this)[0]) {
|
|
// step through so that the UI controller can determine when to show the placeHolder
|
|
var targetOffset = moveVerticalAmount + dragPastBy;
|
|
for (var offset = 0; Math.abs(offset) < Math.abs(targetOffset); offset += (direction === 'down' ? 10 : -10)) {
|
|
// drag move
|
|
dispatchEvent(document, 'mousemove', createEvent('mousemove', document, { clientX: x, clientY: y + offset }));
|
|
}
|
|
dispatchEvent(document, 'mousemove', createEvent('mousemove', document, { clientX: x, clientY: y + targetOffset }));
|
|
} else {
|
|
if (window.console) {
|
|
console.log('Could not move as at top or bottom already');
|
|
}
|
|
}
|
|
|
|
setTimeout(function() {
|
|
dispatchEvent(document, 'mousemove', createEvent('mousemove', document, { clientX: x, clientY: y + moveVerticalAmount }));
|
|
}, 5);
|
|
setTimeout(function() {
|
|
dispatchEvent(handle, 'mouseup', createEvent('mouseup', handle, { clientX: x, clientY: y + moveVerticalAmount }));
|
|
}, 10);
|
|
});
|
|
};
|
|
|
|
function createEvent(type, target, options) {
|
|
var evt;
|
|
var e = $.extend({
|
|
target: target,
|
|
preventDefault: function() { },
|
|
stopImmediatePropagation: function() { },
|
|
stopPropagation: function() { },
|
|
isPropagationStopped: function() { return true; },
|
|
isImmediatePropagationStopped: function() { return true; },
|
|
isDefaultPrevented: function() { return true; },
|
|
bubbles: true,
|
|
cancelable: (type != "mousemove"),
|
|
view: window,
|
|
detail: 0,
|
|
screenX: 0,
|
|
screenY: 0,
|
|
clientX: 0,
|
|
clientY: 0,
|
|
ctrlKey: false,
|
|
altKey: false,
|
|
shiftKey: false,
|
|
metaKey: false,
|
|
button: 0,
|
|
relatedTarget: undefined
|
|
}, options || {});
|
|
|
|
if ($.isFunction(document.createEvent)) {
|
|
evt = document.createEvent("MouseEvents");
|
|
evt.initMouseEvent(type, e.bubbles, e.cancelable, e.view, e.detail,
|
|
e.screenX, e.screenY, e.clientX, e.clientY,
|
|
e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
|
|
e.button, e.relatedTarget || document.body.parentNode);
|
|
} else if (document.createEventObject) {
|
|
evt = document.createEventObject();
|
|
$.extend(evt, e);
|
|
evt.button = { 0:1, 1:4, 2:2 }[evt.button] || evt.button;
|
|
}
|
|
return evt;
|
|
}
|
|
|
|
function dispatchEvent(el, type, evt) {
|
|
if (el.dispatchEvent) {
|
|
el.dispatchEvent(evt);
|
|
} else if (el.fireEvent) {
|
|
el.fireEvent('on' + type, evt);
|
|
}
|
|
return evt;
|
|
}
|
|
|
|
function findCenter(el) {
|
|
var el = $(el), o = el.offset();
|
|
return {
|
|
x: o.left + el.outerWidth() / 2,
|
|
y: o.top + el.outerHeight() / 2
|
|
};
|
|
}
|
|
|
|
//
|
|
// plugin defaults
|
|
//
|
|
$.fn.simulateDragSortable.defaults = {
|
|
move: 0
|
|
};
|
|
})(jQuery); |