You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1046 lines
23 KiB

11 years ago
/**!
* Sortable
* @author RubaXa <trash@rubaxa.org>
* @license MIT
*/
10 years ago
(function (factory) {
11 years ago
"use strict";
10 years ago
if (typeof define === "function" && define.amd) {
11 years ago
define(factory);
11 years ago
}
10 years ago
else if (typeof module != "undefined" && typeof module.exports != "undefined") {
module.exports = factory();
}
10 years ago
else if (typeof Package !== "undefined") {
Sortable = factory(); // export for Meteor.js
}
11 years ago
else {
10 years ago
/* jshint sub:true */
11 years ago
window["Sortable"] = factory();
}
10 years ago
})(function () {
11 years ago
"use strict";
10 years ago
var dragEl,
ghostEl,
cloneEl,
rootEl,
nextEl,
11 years ago
scrollEl,
scrollParentEl,
10 years ago
lastEl,
lastCSS,
11 years ago
10 years ago
oldIndex,
newIndex,
10 years ago
activeGroup,
autoScroll = {},
11 years ago
10 years ago
tapEvt,
touchEvt,
11 years ago
10 years ago
expando = 'Sortable' + (new Date).getTime(),
11 years ago
10 years ago
win = window,
document = win.document,
parseInt = win.parseInt,
10 years ago
supportDraggable = !!('draggable' in document.createElement('div')),
10 years ago
_silent = false,
_dispatchEvent = function (rootEl, name, targetEl, fromEl, startIndex, newIndex) {
var evt = document.createEvent('Event');
11 years ago
evt.initEvent(name, true, true);
10 years ago
evt.item = targetEl || rootEl;
evt.from = fromEl || rootEl;
evt.clone = cloneEl;
10 years ago
evt.oldIndex = startIndex;
evt.newIndex = newIndex;
rootEl.dispatchEvent(evt);
10 years ago
},
10 years ago
_customEvents = 'onAdd onUpdate onRemove onStart onEnd onFilter onSort'.split(' '),
11 years ago
10 years ago
noop = function () {},
abs = Math.abs,
10 years ago
slice = [].slice,
11 years ago
touchDragOverListeners = [],
_autoScroll = _throttle(function (/**Event*/evt, /**Object*/options, /**HTMLElement*/rootEl) {
// Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521
if (rootEl && options.scroll) {
var el,
rect,
sens = options.scrollSensitivity,
speed = options.scrollSpeed,
x = evt.clientX,
y = evt.clientY,
winWidth = window.innerWidth,
winHeight = window.innerHeight,
vx,
vy
;
// Delect scrollEl
if (scrollParentEl !== rootEl) {
scrollEl = options.scroll;
scrollParentEl = rootEl;
if (scrollEl === true) {
scrollEl = rootEl;
do {
if ((scrollEl.offsetWidth < scrollEl.scrollWidth) ||
(scrollEl.offsetHeight < scrollEl.scrollHeight)
) {
break;
}
/* jshint boss:true */
} while (scrollEl = scrollEl.parentNode);
}
}
if (scrollEl) {
el = scrollEl;
rect = scrollEl.getBoundingClientRect();
vx = (abs(rect.right - x) <= sens) - (abs(rect.left - x) <= sens);
vy = (abs(rect.bottom - y) <= sens) - (abs(rect.top - y) <= sens);
}
if (!(vx || vy)) {
vx = (winWidth - x <= sens) - (x <= sens);
vy = (winHeight - y <= sens) - (y <= sens);
/* jshint expr:true */
(vx || vy) && (el = win);
}
if (autoScroll.vx !== vx || autoScroll.vy !== vy || autoScroll.el !== el) {
autoScroll.el = el;
autoScroll.vx = vx;
autoScroll.vy = vy;
clearInterval(autoScroll.pid);
if (el) {
autoScroll.pid = setInterval(function () {
if (el === win) {
win.scrollTo(win.scrollX + vx * speed, win.scrollY + vy * speed);
} else {
vy && (el.scrollTop += vy * speed);
vx && (el.scrollLeft += vx * speed);
}
}, 24);
}
}
}
}, 30)
11 years ago
;
11 years ago
/**
* @class Sortable
* @param {HTMLElement} el
* @param {Object} [options]
11 years ago
*/
10 years ago
function Sortable(el, options) {
11 years ago
this.el = el; // root element
this.options = options = (options || {});
// Default options
var defaults = {
group: Math.random(),
sort: true,
disabled: false,
store: null,
handle: null,
scroll: true,
scrollSensitivity: 30,
scrollSpeed: 10,
draggable: /[uo]l/i.test(el.nodeName) ? 'li' : '>*',
ghostClass: 'sortable-ghost',
ignore: 'a, img',
filter: null,
animation: 0,
setData: function (dataTransfer, dragEl) {
dataTransfer.setData('Text', dragEl.textContent);
},
dropBubble: false,
dragoverBubble: false
};
// Set default options
for (var name in defaults) {
!(name in options) && (options[name] = defaults[name]);
}
11 years ago
var group = options.group;
if (!group || typeof group != 'object') {
group = options.group = { name: group };
}
['pull', 'put'].forEach(function (key) {
if (!(key in group)) {
group[key] = true;
}
});
// Define events
_customEvents.forEach(function (name) {
options[name] = _bind(this, options[name] || noop);
_on(el, name.substr(2).toLowerCase(), options[name]);
}, this);
11 years ago
// Export options
options.groups = ' ' + group.name + (group.put.join ? ' ' + group.put.join(' ') : '') + ' ';
el[expando] = options;
11 years ago
11 years ago
// Bind all private methods
10 years ago
for (var fn in this) {
if (fn.charAt(0) === '_') {
11 years ago
this[fn] = _bind(this, this[fn]);
}
}
// Bind events
_on(el, 'mousedown', this._onTapStart);
_on(el, 'touchstart', this._onTapStart);
_on(el, 'dragover', this);
_on(el, 'dragenter', this);
11 years ago
touchDragOverListeners.push(this._onDragOver);
// Restore sorting
options.store && this.sort(options.store.get(this));
11 years ago
}
Sortable.prototype = /** @lends Sortable.prototype */ {
11 years ago
constructor: Sortable,
_dragStarted: function () {
if (rootEl && dragEl) {
// Apply effect
_toggleClass(dragEl, this.options.ghostClass, true);
Sortable.active = this;
// Drag start event
_dispatchEvent(rootEl, 'start', dragEl, rootEl, oldIndex);
}
11 years ago
},
10 years ago
_onTapStart: function (/**Event|TouchEvent*/evt) {
var type = evt.type,
touch = evt.touches && evt.touches[0],
10 years ago
target = (touch || evt).target,
originalTarget = target,
10 years ago
options = this.options,
el = this.el,
filter = options.filter;
11 years ago
if (type === 'mousedown' && evt.button !== 0 || options.disabled) {
return; // only left button or enabled
}
if (options.handle) {
target = _closest(target, options.handle, el);
}
target = _closest(target, options.draggable, el);
// get the index of the dragged element within its parent
10 years ago
oldIndex = _index(target);
// Check filter
10 years ago
if (typeof filter === 'function') {
if (filter.call(this, evt, target, this)) {
10 years ago
_dispatchEvent(originalTarget, 'filter', target, el, oldIndex);
evt.preventDefault();
return; // cancel dnd
}
}
10 years ago
else if (filter) {
filter = filter.split(',').some(function (criteria) {
criteria = _closest(originalTarget, criteria.trim(), el);
if (criteria) {
10 years ago
_dispatchEvent(criteria, 'filter', target, el, oldIndex);
return true;
}
});
if (filter) {
evt.preventDefault();
return; // cancel dnd
}
}
// Prepare `dragstart`
10 years ago
if (target && !dragEl && (target.parentNode === el)) {
11 years ago
tapEvt = evt;
rootEl = this.el;
dragEl = target;
nextEl = dragEl.nextSibling;
activeGroup = this.options.group;
dragEl.draggable = true;
11 years ago
// Disable "draggable"
options.ignore.split(',').forEach(function (criteria) {
_find(target, criteria.trim(), _disableDraggable);
});
11 years ago
10 years ago
if (touch) {
11 years ago
// Touch device support
tapEvt = {
10 years ago
target: target,
clientX: touch.clientX,
clientY: touch.clientY
11 years ago
};
10 years ago
this._onDragStart(tapEvt, 'touch');
11 years ago
evt.preventDefault();
}
10 years ago
_on(document, 'mouseup', this._onDrop);
_on(document, 'touchend', this._onDrop);
_on(document, 'touchcancel', this._onDrop);
11 years ago
_on(dragEl, 'dragend', this);
_on(rootEl, 'dragstart', this._onDragStart);
10 years ago
if (!supportDraggable) {
this._onDragStart(tapEvt, true);
}
11 years ago
try {
10 years ago
if (document.selection) {
11 years ago
document.selection.empty();
} else {
10 years ago
window.getSelection().removeAllRanges();
11 years ago
}
10 years ago
} catch (err) {
}
11 years ago
}
},
10 years ago
_emulateDragOver: function () {
if (touchEvt) {
11 years ago
_css(ghostEl, 'display', 'none');
10 years ago
var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY),
parent = target,
groupName = ' ' + this.options.group.name + '',
10 years ago
i = touchDragOverListeners.length;
11 years ago
if (parent) {
do {
if (parent[expando] && parent[expando].groups.indexOf(groupName) > -1) {
while (i--) {
touchDragOverListeners[i]({
clientX: touchEvt.clientX,
clientY: touchEvt.clientY,
target: target,
rootEl: parent
});
}
break;
}
target = parent; // store last element
11 years ago
}
/* jshint boss:true */
while (parent = parent.parentNode);
11 years ago
}
_css(ghostEl, 'display', '');
}
},
10 years ago
_onTouchMove: function (/**TouchEvent*/evt) {
if (tapEvt) {
10 years ago
var touch = evt.touches ? evt.touches[0] : evt,
10 years ago
dx = touch.clientX - tapEvt.clientX,
dy = touch.clientY - tapEvt.clientY,
10 years ago
translate3d = evt.touches ? 'translate3d(' + dx + 'px,' + dy + 'px,0)' : 'translate(' + dx + 'px,' + dy + 'px)';
11 years ago
touchEvt = touch;
10 years ago
_css(ghostEl, 'webkitTransform', translate3d);
_css(ghostEl, 'mozTransform', translate3d);
_css(ghostEl, 'msTransform', translate3d);
_css(ghostEl, 'transform', translate3d);
11 years ago
evt.preventDefault();
11 years ago
}
},
10 years ago
_onDragStart: function (/**Event*/evt, /**boolean*/useFallback) {
var dataTransfer = evt.dataTransfer,
options = this.options;
11 years ago
this._offUpEvents();
11 years ago
if (activeGroup.pull == 'clone') {
cloneEl = dragEl.cloneNode(true);
_css(cloneEl, 'display', 'none');
rootEl.insertBefore(cloneEl, dragEl);
}
10 years ago
if (useFallback) {
10 years ago
var rect = dragEl.getBoundingClientRect(),
css = _css(dragEl),
ghostRect;
11 years ago
ghostEl = dragEl.cloneNode(true);
11 years ago
_css(ghostEl, 'top', rect.top - parseInt(css.marginTop, 10));
_css(ghostEl, 'left', rect.left - parseInt(css.marginLeft, 10));
11 years ago
_css(ghostEl, 'width', rect.width);
_css(ghostEl, 'height', rect.height);
11 years ago
_css(ghostEl, 'opacity', '0.8');
_css(ghostEl, 'position', 'fixed');
_css(ghostEl, 'zIndex', '100000');
11 years ago
rootEl.appendChild(ghostEl);
// Fixing dimensions.
ghostRect = ghostEl.getBoundingClientRect();
10 years ago
_css(ghostEl, 'width', rect.width * 2 - ghostRect.width);
_css(ghostEl, 'height', rect.height * 2 - ghostRect.height);
11 years ago
10 years ago
if (useFallback === 'touch') {
// Bind touch events
_on(document, 'touchmove', this._onTouchMove);
_on(document, 'touchend', this._onDrop);
_on(document, 'touchcancel', this._onDrop);
} else {
// Old brwoser
_on(document, 'mousemove', this._onTouchMove);
_on(document, 'mouseup', this._onDrop);
}
11 years ago
this._loopId = setInterval(this._emulateDragOver, 150);
11 years ago
}
else {
if (dataTransfer) {
dataTransfer.effectAllowed = 'move';
options.setData && options.setData.call(this, dataTransfer, dragEl);
}
11 years ago
_on(document, 'drop', this);
11 years ago
}
setTimeout(this._dragStarted, 0);
11 years ago
},
10 years ago
_onDragOver: function (/**Event*/evt) {
var el = this.el,
target,
dragRect,
revert,
options = this.options,
group = options.group,
groupPut = group.put,
isOwner = (activeGroup === group),
canSort = options.sort;
if (evt.dataTransfer && evt.dataTransfer.effectAllowed !== 'move') {
return;
}
if (evt.preventDefault !== void 0) {
evt.preventDefault();
!options.dragoverBubble && evt.stopPropagation();
}
10 years ago
if (activeGroup && !options.disabled &&
(isOwner
? canSort || (revert = !rootEl.contains(dragEl))
: activeGroup.pull && groupPut && (
(activeGroup.name === group.name) || // by Name
(groupPut.indexOf && ~groupPut.indexOf(activeGroup.name)) // by Array
)
) &&
(evt.rootEl === void 0 || evt.rootEl === this.el)
10 years ago
) {
10 years ago
// Smart auto-scrolling
_autoScroll(evt, options, this.el);
if (_silent) {
return;
}
target = _closest(evt.target, options.draggable, el);
dragRect = dragEl.getBoundingClientRect();
if (revert) {
_cloneHide(true);
if (cloneEl || nextEl) {
rootEl.insertBefore(dragEl, cloneEl || nextEl);
}
else if (!canSort) {
rootEl.appendChild(dragEl);
}
return;
}
11 years ago
10 years ago
if ((el.children.length === 0) || (el.children[0] === ghostEl) ||
(el === evt.target) && (target = _ghostInBottom(el, evt))
10 years ago
) {
if (target) {
if (target.animated) {
return;
}
targetRect = target.getBoundingClientRect();
}
11 years ago
_cloneHide(isOwner);
el.appendChild(dragEl);
10 years ago
this._animate(dragRect, dragEl);
10 years ago
target && this._animate(targetRect, target);
}
10 years ago
else if (target && !target.animated && target !== dragEl && (target.parentNode[expando] !== void 0)) {
if (lastEl !== target) {
lastEl = target;
lastCSS = _css(target);
11 years ago
}
10 years ago
var targetRect = target.getBoundingClientRect(),
width = targetRect.right - targetRect.left,
height = targetRect.bottom - targetRect.top,
floating = /left|right|inline/.test(lastCSS.cssFloat + lastCSS.display),
isWide = (target.offsetWidth > dragEl.offsetWidth),
isLong = (target.offsetHeight > dragEl.offsetHeight),
halfway = (floating ? (evt.clientX - targetRect.left) / width : (evt.clientY - targetRect.top) / height) > 0.5,
nextSibling = target.nextElementSibling,
after
;
_silent = true;
setTimeout(_unsilent, 30);
_cloneHide(isOwner);
10 years ago
if (floating) {
after = (target.previousElementSibling === dragEl) && !isWide || halfway && isWide;
} else {
10 years ago
after = (nextSibling !== dragEl) && !isLong || halfway && isLong;
}
10 years ago
if (after && !nextSibling) {
el.appendChild(dragEl);
} else {
target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
11 years ago
}
10 years ago
this._animate(dragRect, dragEl);
this._animate(targetRect, target);
11 years ago
}
}
},
_animate: function (prevRect, target) {
var ms = this.options.animation;
if (ms) {
var currentRect = target.getBoundingClientRect();
_css(target, 'transition', 'none');
_css(target, 'transform', 'translate3d('
+ (prevRect.left - currentRect.left) + 'px,'
+ (prevRect.top - currentRect.top) + 'px,0)'
);
target.offsetWidth; // repaint
_css(target, 'transition', 'all ' + ms + 'ms');
_css(target, 'transform', 'translate3d(0,0,0)');
10 years ago
clearTimeout(target.animated);
target.animated = setTimeout(function () {
_css(target, 'transition', '');
_css(target, 'transform', '');
target.animated = false;
}, ms);
}
},
_offUpEvents: function () {
_off(document, 'mouseup', this._onDrop);
_off(document, 'touchmove', this._onTouchMove);
_off(document, 'touchend', this._onDrop);
_off(document, 'touchcancel', this._onDrop);
},
11 years ago
10 years ago
_onDrop: function (/**Event*/evt) {
var el = this.el,
options = this.options;
11 years ago
clearInterval(this._loopId);
clearInterval(autoScroll.pid);
11 years ago
// Unbind events
_off(document, 'drop', this);
_off(document, 'mousemove', this._onTouchMove);
_off(el, 'dragstart', this._onDragStart);
11 years ago
this._offUpEvents();
11 years ago
10 years ago
if (evt) {
11 years ago
evt.preventDefault();
!options.dropBubble && evt.stopPropagation();
11 years ago
ghostEl && ghostEl.parentNode.removeChild(ghostEl);
11 years ago
10 years ago
if (dragEl) {
_off(dragEl, 'dragend', this);
_disableDraggable(dragEl);
11 years ago
_toggleClass(dragEl, this.options.ghostClass, false);
if (rootEl !== dragEl.parentNode) {
10 years ago
newIndex = _index(dragEl);
// drag from one list and drop into another
10 years ago
_dispatchEvent(dragEl.parentNode, 'sort', dragEl, rootEl, oldIndex, newIndex);
_dispatchEvent(rootEl, 'sort', dragEl, rootEl, oldIndex, newIndex);
11 years ago
// Add event
10 years ago
_dispatchEvent(dragEl, 'add', dragEl, rootEl, oldIndex, newIndex);
// Remove event
10 years ago
_dispatchEvent(rootEl, 'remove', dragEl, rootEl, oldIndex, newIndex);
11 years ago
}
else {
// Remove clone
cloneEl && cloneEl.parentNode.removeChild(cloneEl);
10 years ago
if (dragEl.nextSibling !== nextEl) {
// Get the index of the dragged element within its parent
newIndex = _index(dragEl);
10 years ago
// drag & drop within the same list
_dispatchEvent(rootEl, 'update', dragEl, rootEl, oldIndex, newIndex);
_dispatchEvent(rootEl, 'sort', dragEl, rootEl, oldIndex, newIndex);
}
11 years ago
}
10 years ago
// Drag end event
10 years ago
Sortable.active && _dispatchEvent(rootEl, 'end', dragEl, rootEl, oldIndex, newIndex);
11 years ago
}
// Nulling
11 years ago
rootEl =
dragEl =
ghostEl =
nextEl =
cloneEl =
11 years ago
scrollEl =
scrollParentEl =
11 years ago
tapEvt =
touchEvt =
lastEl =
lastCSS =
activeGroup =
Sortable.active = null;
// Save sorting
10 years ago
this.save();
11 years ago
}
},
handleEvent: function (/**Event*/evt) {
var type = evt.type;
if (type === 'dragover' || type === 'dragenter') {
this._onDragOver(evt);
_globalDragOver(evt);
}
else if (type === 'drop' || type === 'dragend') {
this._onDrop(evt);
}
},
/**
* Serializes the item into an array of string.
* @returns {String[]}
*/
toArray: function () {
var order = [],
el,
children = this.el.children,
i = 0,
10 years ago
n = children.length;
for (; i < n; i++) {
el = children[i];
if (_closest(el, this.options.draggable, this.el)) {
order.push(el.getAttribute('data-id') || _generateId(el));
}
}
return order;
},
/**
* Sorts the elements according to the array.
* @param {String[]} order order of the items
*/
sort: function (order) {
var items = {}, rootEl = this.el;
this.toArray().forEach(function (id, i) {
var el = rootEl.children[i];
if (_closest(el, this.options.draggable, rootEl)) {
items[id] = el;
}
}, this);
order.forEach(function (id) {
if (items[id]) {
rootEl.removeChild(items[id]);
rootEl.appendChild(items[id]);
}
});
},
/**
* Save the current sorting
*/
save: function () {
var store = this.options.store;
store && store.set(this);
},
/**
* For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
* @param {HTMLElement} el
* @param {String} [selector] default: `options.draggable`
* @returns {HTMLElement|null}
*/
closest: function (el, selector) {
return _closest(el, selector || this.options.draggable, this.el);
},
/**
* Set/get option
* @param {string} name
* @param {*} [value]
* @returns {*}
*/
option: function (name, value) {
var options = this.options;
if (value === void 0) {
return options[name];
} else {
options[name] = value;
}
},
/**
* Destroy
*/
destroy: function () {
11 years ago
var el = this.el, options = this.options;
_customEvents.forEach(function (name) {
_off(el, name.substr(2).toLowerCase(), options[name]);
});
11 years ago
_off(el, 'mousedown', this._onTapStart);
_off(el, 'touchstart', this._onTapStart);
_off(el, 'dragover', this);
_off(el, 'dragenter', this);
11 years ago
//remove draggable attributes
10 years ago
Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) {
el.removeAttribute('draggable');
});
11 years ago
touchDragOverListeners.splice(touchDragOverListeners.indexOf(this._onDragOver), 1);
this._onDrop();
this.el = null;
}
};
function _cloneHide(state) {
if (cloneEl && (cloneEl.state !== state)) {
_css(cloneEl, 'display', state ? 'none' : '');
!state && cloneEl.state && rootEl.insertBefore(cloneEl, dragEl);
cloneEl.state = state;
}
}
10 years ago
function _bind(ctx, fn) {
11 years ago
var args = slice.call(arguments, 2);
10 years ago
return fn.bind ? fn.bind.apply(fn, [ctx].concat(args)) : function () {
11 years ago
return fn.apply(ctx, args.concat(slice.call(arguments)));
};
}
function _closest(/**HTMLElement*/el, /**String*/selector, /**HTMLElement*/ctx) {
if (el) {
11 years ago
ctx = ctx || document;
selector = selector.split('.');
10 years ago
var tag = selector.shift().toUpperCase(),
re = new RegExp('\\s(' + selector.join('|') + ')\\s', 'g');
11 years ago
do {
10 years ago
if (
(tag === '>*' && el.parentNode === ctx) || (
(tag === '' || el.nodeName.toUpperCase() == tag) &&
(!selector.length || ((' ' + el.className + ' ').match(re) || []).length == selector.length)
)
10 years ago
) {
return el;
11 years ago
}
}
10 years ago
while (el !== ctx && (el = el.parentNode));
11 years ago
}
10 years ago
return null;
11 years ago
}
function _globalDragOver(/**Event*/evt) {
11 years ago
evt.dataTransfer.dropEffect = 'move';
evt.preventDefault();
}
10 years ago
function _on(el, event, fn) {
11 years ago
el.addEventListener(event, fn, false);
}
10 years ago
function _off(el, event, fn) {
11 years ago
el.removeEventListener(event, fn, false);
}
10 years ago
function _toggleClass(el, name, state) {
if (el) {
if (el.classList) {
11 years ago
el.classList[state ? 'add' : 'remove'](name);
}
else {
10 years ago
var className = (' ' + el.className + ' ').replace(/\s+/g, ' ').replace(' ' + name + ' ', '');
el.className = className + (state ? ' ' + name : '');
11 years ago
}
}
}
10 years ago
function _css(el, prop, val) {
var style = el && el.style;
10 years ago
if (style) {
if (val === void 0) {
if (document.defaultView && document.defaultView.getComputedStyle) {
11 years ago
val = document.defaultView.getComputedStyle(el, '');
}
10 years ago
else if (el.currentStyle) {
val = el.currentStyle;
11 years ago
}
return prop === void 0 ? val : val[prop];
}
else {
if (!(prop in style)) {
prop = '-webkit-' + prop;
}
style[prop] = val + (typeof val === 'string' ? '' : 'px');
11 years ago
}
}
}
10 years ago
function _find(ctx, tagName, iterator) {
if (ctx) {
11 years ago
var list = ctx.getElementsByTagName(tagName), i = 0, n = list.length;
10 years ago
if (iterator) {
for (; i < n; i++) {
11 years ago
iterator(list[i], i);
}
}
10 years ago
return list;
11 years ago
}
10 years ago
return [];
11 years ago
}
10 years ago
function _disableDraggable(el) {
el.draggable = false;
11 years ago
}
10 years ago
function _unsilent() {
_silent = false;
}
/** @returns {HTMLElement|false} */
10 years ago
function _ghostInBottom(el, evt) {
var lastEl = el.lastElementChild, rect = lastEl.getBoundingClientRect();
return (evt.clientY - (rect.top + rect.height) > 5) && lastEl; // min delta
}
/**
* Generate id
* @param {HTMLElement} el
* @returns {String}
* @private
*/
function _generateId(el) {
var str = el.tagName + el.className + el.src + el.href + el.textContent,
i = str.length,
10 years ago
sum = 0;
while (i--) {
sum += str.charCodeAt(i);
}
return sum.toString(36);
}
/**
* Returns the index of an element within its parent
* @param el
* @returns {number}
* @private
*/
function _index(/**HTMLElement*/el) {
var index = 0;
while (el && (el = el.previousElementSibling)) {
if (el.nodeName.toUpperCase() !== 'TEMPLATE') {
index++;
}
}
return index;
}
11 years ago
function _throttle(callback, ms) {
var args, _this;
return function () {
if (args === void 0) {
args = arguments;
_this = this;
setTimeout(function () {
if (args.length === 1) {
callback.call(_this, args[0]);
} else {
callback.apply(_this, args);
}
args = void 0;
}, ms);
}
};
}
11 years ago
// Export utils
Sortable.utils = {
on: _on,
off: _off,
css: _css,
find: _find,
bind: _bind,
is: function (el, selector) {
return !!_closest(el, selector, el);
},
throttle: _throttle,
11 years ago
closest: _closest,
toggleClass: _toggleClass,
dispatchEvent: _dispatchEvent,
index: _index
11 years ago
};
Sortable.version = '1.1.0';
11 years ago
/**
* Create sortable instance
* @param {HTMLElement} el
* @param {Object} [options]
*/
Sortable.create = function (el, options) {
10 years ago
return new Sortable(el, options);
};
11 years ago
// Export
return Sortable;
11 years ago
});