admin/public/static/ext/drag-arrange.js

229 lines
6.1 KiB
JavaScript

'use strict';
(function (factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else {
factory(jQuery);
}
}
(function ($) {
var IS_TOUCH_DEVICE = ('ontouchstart' in document.documentElement);
var DRAG_THRESHOLD = 5;
var counter = 0;
var dragEvents = (function () {
if (IS_TOUCH_DEVICE) {
return {
START: 'touchstart',
MOVE: 'touchmove',
END: 'touchend'
};
} else {
return {
START: 'mousedown',
MOVE: 'mousemove',
END: 'mouseup'
};
}
}());
$.fn.arrangeable = function (options) {
var dragging = false;
var $clone;
var dragElement;
var originalClientX, originalClientY;
var $elements;
var touchDown = false;
var leftOffset, topOffset;
var eventNamespace;
var $options = options;
if (typeof options === "string") {
if (options === 'destroy') {
if (this.eq(0).data('drag-arrange-destroy')) {
this.eq(0).data('drag-arrange-destroy')();
}
return this;
}
}
options = $.extend({
"dragEndEvent": "drag.end.arrangeable"
}, options);
var dragEndEvent = options["dragEndEvent"];
$elements = this;
eventNamespace = getEventNamespace();
this.each(function () {
var dragSelector = options.dragSelector;
var self = this;
var $this = $(this);
if (dragSelector) {
$this.on(dragEvents.START + eventNamespace,
dragSelector, dragStartHandler);
} else {
$this.on(dragEvents.START + eventNamespace,
dragStartHandler);
}
function dragStartHandler(e) {
e.stopPropagation();
touchDown = true;
originalClientX = e.clientX
|| e.originalEvent.touches[0].clientX;
originalClientY = e.clientY
|| e.originalEvent.touches[0].clientY;
dragElement = self;
}
});
$(document).on(dragEvents.MOVE + eventNamespace,
dragMoveHandler).on(dragEvents.END + eventNamespace,
dragEndHandler);
function dragMoveHandler(e) {
if (!touchDown) {
return;
}
var $dragElement = $(dragElement);
var dragDistanceX = (e.clientX || e.originalEvent.touches[0].clientX)
- originalClientX;
var dragDistanceY = (e.clientY || e.originalEvent.touches[0].clientY)
- originalClientY;
if (dragging) {
e.stopPropagation();
$clone.css({
left: leftOffset + dragDistanceX,
top: topOffset + dragDistanceY
});
shiftHoveredElement($clone, $dragElement, $elements);
} else if (Math.abs(dragDistanceX) > DRAG_THRESHOLD
|| Math.abs(dragDistanceY) > DRAG_THRESHOLD) {
$clone = clone($dragElement);
leftOffset = dragElement.offsetLeft
- parseInt($dragElement.css('margin-left'))
- parseInt($dragElement.css('padding-left'));
topOffset = dragElement.offsetTop
- parseInt($dragElement.css('margin-top'))
- parseInt($dragElement.css('padding-top'));
$clone.css({
left: leftOffset,
top: topOffset
});
$dragElement.parent().append($clone);
$dragElement.css('visibility', 'hidden');
dragging = true;
}
}
function dragEndHandler(e) {
if (dragging) {
e.stopPropagation();
dragging = false;
$clone.remove();
dragElement.style.visibility = 'visible';
$(dragElement).parent().trigger(dragEndEvent,
[$(dragElement)]);
//拖拽结束后执行回调,传入当前拖拽的对象
if ($options.callback) $options.callback($(dragElement));
}
touchDown = false;
}
function destroy() {
$elements.each(function () {
var dragSelector = options.dragSelector;
var $this = $(this);
if (dragSelector) {
$this.off(dragEvents.START + eventNamespace,
dragSelector);
} else {
$this.off(dragEvents.START + eventNamespace);
}
});
$(document).off(dragEvents.MOVE + eventNamespace).off(
dragEvents.END + eventNamespace);
$elements.eq(0).data('drag-arrange-destroy', null);
$elements = null;
dragMoveHandler = null;
dragEndHandler = null;
}
this.eq(0).data('drag-arrange-destroy', destroy);
};
function clone($element) {
var $clone = $element.clone();
$clone.css({
position: 'absolute',
width: $element.width(),
height: $element.height(),
'z-index': 100000
});
return $clone;
}
function getHoveredElement($clone, $dragElement, $movableElements) {
var cloneOffset = $clone.offset();
var cloneWidth = $clone.width();
var cloneHeight = $clone.height();
var cloneLeftPosition = cloneOffset.left;
var cloneRightPosition = cloneOffset.left + cloneWidth;
var cloneTopPosition = cloneOffset.top;
var cloneBottomPosition = cloneOffset.top + cloneHeight;
var $currentElement;
var horizontalMidPosition, verticalMidPosition;
var offset, overlappingX, overlappingY, inRange;
for (var i = 0; i < $movableElements.length; i++) {
$currentElement = $movableElements.eq(i);
if ($currentElement[0] === $dragElement[0]) {
continue;
}
offset = $currentElement.offset();
horizontalMidPosition = offset.left + 0.5
* $currentElement.width();
verticalMidPosition = offset.top + 0.5
* $currentElement.height();
overlappingX = (horizontalMidPosition < cloneRightPosition)
&& (horizontalMidPosition > cloneLeftPosition);
overlappingY = (verticalMidPosition < cloneBottomPosition)
&& (verticalMidPosition > cloneTopPosition);
inRange = overlappingX && overlappingY;
if (inRange) {
return $currentElement[0];
}
}
}
function shiftHoveredElement($clone, $dragElement, $movableElements) {
var hoveredElement = getHoveredElement($clone, $dragElement,
$movableElements);
if (hoveredElement !== $dragElement[0]) {
var hoveredElementIndex = $movableElements
.index(hoveredElement);
var dragElementIndex = $movableElements.index($dragElement);
if (hoveredElementIndex < dragElementIndex) {
$(hoveredElement).before($dragElement);
} else {
$(hoveredElement).after($dragElement);
}
shiftElementPosition($movableElements, dragElementIndex,
hoveredElementIndex);
}
}
function shiftElementPosition(arr, fromIndex, toIndex) {
var temp = arr.splice(fromIndex, 1)[0];
return arr.splice(toIndex, 0, temp);
}
function getEventNamespace() {
counter += 1;
return '.drag-arrange-' + counter;
}
}));