|
|
|
@ -20,7 +20,7 @@
|
|
|
|
|
})(function sortableFactory() { |
|
|
|
|
"use strict"; |
|
|
|
|
|
|
|
|
|
if (typeof window == "undefined" || !window.document) { |
|
|
|
|
if (typeof window === "undefined" || !window.document) { |
|
|
|
|
return function sortableError() { |
|
|
|
|
throw new Error("Sortable.js requires a window with a document"); |
|
|
|
|
}; |
|
|
|
@ -55,6 +55,8 @@
|
|
|
|
|
|
|
|
|
|
moved, |
|
|
|
|
|
|
|
|
|
forRepaintDummy, |
|
|
|
|
|
|
|
|
|
/** @const */ |
|
|
|
|
R_SPACE = /\s+/g, |
|
|
|
|
R_FLOAT = /left|right|inline/, |
|
|
|
@ -64,13 +66,15 @@
|
|
|
|
|
win = window, |
|
|
|
|
document = win.document, |
|
|
|
|
parseInt = win.parseInt, |
|
|
|
|
setTimeout = win.setTimeout, |
|
|
|
|
|
|
|
|
|
$ = win.jQuery || win.Zepto, |
|
|
|
|
Polymer = win.Polymer, |
|
|
|
|
|
|
|
|
|
captureMode = false, |
|
|
|
|
passiveMode = false, |
|
|
|
|
|
|
|
|
|
supportDraggable = !!('draggable' in document.createElement('div')), |
|
|
|
|
supportDraggable = ('draggable' in document.createElement('div')), |
|
|
|
|
supportCssPointerEvents = (function (el) { |
|
|
|
|
// false when IE11
|
|
|
|
|
if (!!navigator.userAgent.match(/(?:Trident.*rv[ :]?11\.|msie)/i)) { |
|
|
|
@ -89,6 +93,8 @@
|
|
|
|
|
savedInputChecked = [], |
|
|
|
|
touchDragOverListeners = [], |
|
|
|
|
|
|
|
|
|
alwaysFalse = function () { return false; }, |
|
|
|
|
|
|
|
|
|
_autoScroll = _throttle(function (/**Event*/evt, /**Object*/options, /**HTMLElement*/rootEl) { |
|
|
|
|
// Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521
|
|
|
|
|
if (rootEl && options.scroll) { |
|
|
|
@ -178,8 +184,11 @@
|
|
|
|
|
|
|
|
|
|
_prepareGroup = function (options) { |
|
|
|
|
function toFn(value, pull) { |
|
|
|
|
if (value === void 0 || value === true) { |
|
|
|
|
if (value == null || value === true) { |
|
|
|
|
value = group.name; |
|
|
|
|
if (value == null) { |
|
|
|
|
return alwaysFalse; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (typeof value === 'function') { |
|
|
|
@ -214,6 +223,20 @@
|
|
|
|
|
} |
|
|
|
|
; |
|
|
|
|
|
|
|
|
|
// Detect support a passive mode
|
|
|
|
|
try { |
|
|
|
|
window.addEventListener('test', null, Object.defineProperty({}, 'passive', { |
|
|
|
|
get: function () { |
|
|
|
|
// `false`, because everything starts to work incorrectly and instead of d'n'd,
|
|
|
|
|
// begins the page has scrolled.
|
|
|
|
|
passiveMode = false; |
|
|
|
|
captureMode = { |
|
|
|
|
capture: false, |
|
|
|
|
passive: passiveMode |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
})); |
|
|
|
|
} catch (err) {} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @class Sortable |
|
|
|
@ -234,7 +257,7 @@
|
|
|
|
|
|
|
|
|
|
// Default options
|
|
|
|
|
var defaults = { |
|
|
|
|
group: Math.random(), |
|
|
|
|
group: null, |
|
|
|
|
sort: true, |
|
|
|
|
disabled: false, |
|
|
|
|
store: null, |
|
|
|
@ -261,7 +284,8 @@
|
|
|
|
|
fallbackClass: 'sortable-fallback', |
|
|
|
|
fallbackOnBody: false, |
|
|
|
|
fallbackTolerance: 0, |
|
|
|
|
fallbackOffset: {x: 0, y: 0} |
|
|
|
|
fallbackOffset: {x: 0, y: 0}, |
|
|
|
|
supportPointer: Sortable.supportPointer !== false |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -285,7 +309,7 @@
|
|
|
|
|
// Bind events
|
|
|
|
|
_on(el, 'mousedown', this._onTapStart); |
|
|
|
|
_on(el, 'touchstart', this._onTapStart); |
|
|
|
|
_on(el, 'pointerdown', this._onTapStart); |
|
|
|
|
options.supportPointer && _on(el, 'pointerdown', this._onTapStart); |
|
|
|
|
|
|
|
|
|
if (this.nativeDraggable) { |
|
|
|
|
_on(el, 'dragover', this); |
|
|
|
@ -322,7 +346,7 @@
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (type === 'mousedown' && evt.button !== 0 || options.disabled) { |
|
|
|
|
if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) { |
|
|
|
|
return; // only left button or enabled
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -348,7 +372,7 @@
|
|
|
|
|
// Check filter
|
|
|
|
|
if (typeof filter === 'function') { |
|
|
|
|
if (filter.call(this, evt, target, this)) { |
|
|
|
|
_dispatchEvent(_this, originalTarget, 'filter', target, el, startIndex); |
|
|
|
|
_dispatchEvent(_this, originalTarget, 'filter', target, el, el, startIndex); |
|
|
|
|
preventOnFilter && evt.preventDefault(); |
|
|
|
|
return; // cancel dnd
|
|
|
|
|
} |
|
|
|
@ -358,7 +382,7 @@
|
|
|
|
|
criteria = _closest(originalTarget, criteria.trim(), el); |
|
|
|
|
|
|
|
|
|
if (criteria) { |
|
|
|
|
_dispatchEvent(_this, criteria, 'filter', target, el, startIndex); |
|
|
|
|
_dispatchEvent(_this, criteria, 'filter', target, el, el, startIndex); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
@ -398,7 +422,7 @@
|
|
|
|
|
this._lastX = (touch || evt).clientX; |
|
|
|
|
this._lastY = (touch || evt).clientY; |
|
|
|
|
|
|
|
|
|
dragEl.style['will-change'] = 'transform'; |
|
|
|
|
dragEl.style['will-change'] = 'all'; |
|
|
|
|
|
|
|
|
|
dragStartFn = function () { |
|
|
|
|
// Delayed drag has been triggered
|
|
|
|
@ -415,7 +439,7 @@
|
|
|
|
|
_this._triggerDragStart(evt, touch); |
|
|
|
|
|
|
|
|
|
// Drag start event
|
|
|
|
|
_dispatchEvent(_this, rootEl, 'choose', dragEl, rootEl, oldIndex); |
|
|
|
|
_dispatchEvent(_this, rootEl, 'choose', dragEl, rootEl, rootEl, oldIndex); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// Disable "draggable"
|
|
|
|
@ -426,8 +450,8 @@
|
|
|
|
|
_on(ownerDocument, 'mouseup', _this._onDrop); |
|
|
|
|
_on(ownerDocument, 'touchend', _this._onDrop); |
|
|
|
|
_on(ownerDocument, 'touchcancel', _this._onDrop); |
|
|
|
|
_on(ownerDocument, 'pointercancel', _this._onDrop); |
|
|
|
|
_on(ownerDocument, 'selectstart', _this); |
|
|
|
|
options.supportPointer && _on(ownerDocument, 'pointercancel', _this._onDrop); |
|
|
|
|
|
|
|
|
|
if (options.delay) { |
|
|
|
|
// If the user moves the pointer or let go the click or touch
|
|
|
|
@ -438,7 +462,7 @@
|
|
|
|
|
_on(ownerDocument, 'touchcancel', _this._disableDelayedDrag); |
|
|
|
|
_on(ownerDocument, 'mousemove', _this._disableDelayedDrag); |
|
|
|
|
_on(ownerDocument, 'touchmove', _this._disableDelayedDrag); |
|
|
|
|
_on(ownerDocument, 'pointermove', _this._disableDelayedDrag); |
|
|
|
|
options.supportPointer && _on(ownerDocument, 'pointermove', _this._disableDelayedDrag); |
|
|
|
|
|
|
|
|
|
_this._dragStartTimer = setTimeout(dragStartFn, options.delay); |
|
|
|
|
} else { |
|
|
|
@ -485,7 +509,7 @@
|
|
|
|
|
try { |
|
|
|
|
if (document.selection) { |
|
|
|
|
// Timeout neccessary for IE9
|
|
|
|
|
setTimeout(function () { |
|
|
|
|
_nextTick(function () { |
|
|
|
|
document.selection.empty(); |
|
|
|
|
}); |
|
|
|
|
} else { |
|
|
|
@ -506,7 +530,7 @@
|
|
|
|
|
Sortable.active = this; |
|
|
|
|
|
|
|
|
|
// Drag start event
|
|
|
|
|
_dispatchEvent(this, rootEl, 'start', dragEl, rootEl, oldIndex); |
|
|
|
|
_dispatchEvent(this, rootEl, 'start', dragEl, rootEl, rootEl, oldIndex); |
|
|
|
|
} else { |
|
|
|
|
this._nulling(); |
|
|
|
|
} |
|
|
|
@ -525,9 +549,14 @@
|
|
|
|
|
_css(ghostEl, 'display', 'none'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY), |
|
|
|
|
parent = target, |
|
|
|
|
i = touchDragOverListeners.length; |
|
|
|
|
var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY); |
|
|
|
|
var parent = target; |
|
|
|
|
var i = touchDragOverListeners.length; |
|
|
|
|
|
|
|
|
|
if (target && target.shadowRoot) { |
|
|
|
|
target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY); |
|
|
|
|
parent = target; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (parent) { |
|
|
|
|
do { |
|
|
|
@ -625,22 +654,26 @@
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
_onDragStart: function (/**Event*/evt, /**boolean*/useFallback) { |
|
|
|
|
var dataTransfer = evt.dataTransfer, |
|
|
|
|
options = this.options; |
|
|
|
|
var _this = this; |
|
|
|
|
var dataTransfer = evt.dataTransfer; |
|
|
|
|
var options = _this.options; |
|
|
|
|
|
|
|
|
|
this._offUpEvents(); |
|
|
|
|
_this._offUpEvents(); |
|
|
|
|
|
|
|
|
|
if (activeGroup.checkPull(this, this, dragEl, evt)) { |
|
|
|
|
if (activeGroup.checkPull(_this, _this, dragEl, evt)) { |
|
|
|
|
cloneEl = _clone(dragEl); |
|
|
|
|
|
|
|
|
|
cloneEl.draggable = false; |
|
|
|
|
cloneEl.style['will-change'] = ''; |
|
|
|
|
|
|
|
|
|
_css(cloneEl, 'display', 'none'); |
|
|
|
|
_toggleClass(cloneEl, this.options.chosenClass, false); |
|
|
|
|
_toggleClass(cloneEl, _this.options.chosenClass, false); |
|
|
|
|
|
|
|
|
|
rootEl.insertBefore(cloneEl, dragEl); |
|
|
|
|
_dispatchEvent(this, rootEl, 'clone', dragEl); |
|
|
|
|
// #1143: IFrame support workaround
|
|
|
|
|
_this._cloneId = _nextTick(function () { |
|
|
|
|
rootEl.insertBefore(cloneEl, dragEl); |
|
|
|
|
_dispatchEvent(_this, rootEl, 'clone', dragEl); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
_toggleClass(dragEl, options.dragClass, true); |
|
|
|
@ -648,27 +681,36 @@
|
|
|
|
|
if (useFallback) { |
|
|
|
|
if (useFallback === 'touch') { |
|
|
|
|
// Bind touch events
|
|
|
|
|
_on(document, 'touchmove', this._onTouchMove); |
|
|
|
|
_on(document, 'touchend', this._onDrop); |
|
|
|
|
_on(document, 'touchcancel', this._onDrop); |
|
|
|
|
_on(document, 'pointermove', this._onTouchMove); |
|
|
|
|
_on(document, 'pointerup', this._onDrop); |
|
|
|
|
_on(document, 'touchmove', _this._onTouchMove); |
|
|
|
|
_on(document, 'touchend', _this._onDrop); |
|
|
|
|
_on(document, 'touchcancel', _this._onDrop); |
|
|
|
|
|
|
|
|
|
if (options.supportPointer) { |
|
|
|
|
_on(document, 'pointermove', _this._onTouchMove); |
|
|
|
|
_on(document, 'pointerup', _this._onDrop); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// Old brwoser
|
|
|
|
|
_on(document, 'mousemove', this._onTouchMove); |
|
|
|
|
_on(document, 'mouseup', this._onDrop); |
|
|
|
|
_on(document, 'mousemove', _this._onTouchMove); |
|
|
|
|
_on(document, 'mouseup', _this._onDrop); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this._loopId = setInterval(this._emulateDragOver, 50); |
|
|
|
|
_this._loopId = setInterval(_this._emulateDragOver, 50); |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
if (dataTransfer) { |
|
|
|
|
dataTransfer.effectAllowed = 'move'; |
|
|
|
|
options.setData && options.setData.call(this, dataTransfer, dragEl); |
|
|
|
|
options.setData && options.setData.call(_this, dataTransfer, dragEl); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
_on(document, 'drop', this); |
|
|
|
|
setTimeout(this._dragStarted, 0); |
|
|
|
|
_on(document, 'drop', _this); |
|
|
|
|
|
|
|
|
|
// #1143: Бывает элемент с IFrame внутри блокирует `drop`,
|
|
|
|
|
// поэтому если вызвался `mouseover`, значит надо отменять весь d'n'd.
|
|
|
|
|
// Breaking Chrome 62+
|
|
|
|
|
// _on(document, 'mouseover', _this);
|
|
|
|
|
|
|
|
|
|
_this._dragStartId = _nextTick(_this._dragStarted); |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
@ -848,7 +890,7 @@
|
|
|
|
|
+ (prevRect.top - currentRect.top) + 'px,0)' |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
target.offsetWidth; // repaint
|
|
|
|
|
forRepaintDummy = target.offsetWidth; // repaint
|
|
|
|
|
|
|
|
|
|
_css(target, 'transition', 'all ' + ms + 'ms'); |
|
|
|
|
_css(target, 'transform', 'translate3d(0,0,0)'); |
|
|
|
@ -883,7 +925,11 @@
|
|
|
|
|
clearInterval(autoScroll.pid); |
|
|
|
|
clearTimeout(this._dragStartTimer); |
|
|
|
|
|
|
|
|
|
_cancelNextTick(this._cloneId); |
|
|
|
|
_cancelNextTick(this._dragStartId); |
|
|
|
|
|
|
|
|
|
// Unbind events
|
|
|
|
|
_off(document, 'mouseover', this); |
|
|
|
|
_off(document, 'mousemove', this._onTouchMove); |
|
|
|
|
|
|
|
|
|
if (this.nativeDraggable) { |
|
|
|
@ -899,11 +945,11 @@
|
|
|
|
|
!options.dropBubble && evt.stopPropagation(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ghostEl && ghostEl.parentNode.removeChild(ghostEl); |
|
|
|
|
ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl); |
|
|
|
|
|
|
|
|
|
if (rootEl === parentEl || Sortable.active.lastPullMode !== 'clone') { |
|
|
|
|
// Remove clone
|
|
|
|
|
cloneEl && cloneEl.parentNode.removeChild(cloneEl); |
|
|
|
|
cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (dragEl) { |
|
|
|
@ -919,21 +965,21 @@
|
|
|
|
|
_toggleClass(dragEl, this.options.chosenClass, false); |
|
|
|
|
|
|
|
|
|
// Drag stop event
|
|
|
|
|
_dispatchEvent(this, rootEl, 'unchoose', dragEl, rootEl, oldIndex, null, evt); |
|
|
|
|
_dispatchEvent(this, rootEl, 'unchoose', dragEl, parentEl, rootEl, oldIndex, null, evt); |
|
|
|
|
|
|
|
|
|
if (rootEl !== parentEl) { |
|
|
|
|
newIndex = _index(dragEl, options.draggable); |
|
|
|
|
|
|
|
|
|
if (newIndex >= 0) { |
|
|
|
|
// Add event
|
|
|
|
|
_dispatchEvent(null, parentEl, 'add', dragEl, rootEl, oldIndex, newIndex, evt); |
|
|
|
|
_dispatchEvent(null, parentEl, 'add', dragEl, parentEl, rootEl, oldIndex, newIndex, evt); |
|
|
|
|
|
|
|
|
|
// Remove event
|
|
|
|
|
_dispatchEvent(this, rootEl, 'remove', dragEl, rootEl, oldIndex, newIndex, evt); |
|
|
|
|
_dispatchEvent(this, rootEl, 'remove', dragEl, parentEl, rootEl, oldIndex, newIndex, evt); |
|
|
|
|
|
|
|
|
|
// drag from one list and drop into another
|
|
|
|
|
_dispatchEvent(null, parentEl, 'sort', dragEl, rootEl, oldIndex, newIndex, evt); |
|
|
|
|
_dispatchEvent(this, rootEl, 'sort', dragEl, rootEl, oldIndex, newIndex, evt); |
|
|
|
|
_dispatchEvent(null, parentEl, 'sort', dragEl, parentEl, rootEl, oldIndex, newIndex, evt); |
|
|
|
|
_dispatchEvent(this, rootEl, 'sort', dragEl, parentEl, rootEl, oldIndex, newIndex, evt); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
@ -943,8 +989,8 @@
|
|
|
|
|
|
|
|
|
|
if (newIndex >= 0) { |
|
|
|
|
// drag & drop within the same list
|
|
|
|
|
_dispatchEvent(this, rootEl, 'update', dragEl, rootEl, oldIndex, newIndex, evt); |
|
|
|
|
_dispatchEvent(this, rootEl, 'sort', dragEl, rootEl, oldIndex, newIndex, evt); |
|
|
|
|
_dispatchEvent(this, rootEl, 'update', dragEl, parentEl, rootEl, oldIndex, newIndex, evt); |
|
|
|
|
_dispatchEvent(this, rootEl, 'sort', dragEl, parentEl, rootEl, oldIndex, newIndex, evt); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -955,7 +1001,7 @@
|
|
|
|
|
newIndex = oldIndex; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
_dispatchEvent(this, rootEl, 'end', dragEl, rootEl, oldIndex, newIndex, evt); |
|
|
|
|
_dispatchEvent(this, rootEl, 'end', dragEl, parentEl, rootEl, oldIndex, newIndex, evt); |
|
|
|
|
|
|
|
|
|
// Save sorting
|
|
|
|
|
this.save(); |
|
|
|
@ -1013,6 +1059,10 @@
|
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case 'mouseover': |
|
|
|
|
this._onDrop(evt); |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case 'selectstart': |
|
|
|
|
evt.preventDefault(); |
|
|
|
|
break; |
|
|
|
@ -1260,7 +1310,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function _dispatchEvent(sortable, rootEl, name, targetEl, fromEl, startIndex, newIndex, originalEvt) { |
|
|
|
|
function _dispatchEvent(sortable, rootEl, name, targetEl, toEl, fromEl, startIndex, newIndex, originalEvt) { |
|
|
|
|
sortable = (sortable || rootEl[expando]); |
|
|
|
|
|
|
|
|
|
var evt = document.createEvent('Event'), |
|
|
|
@ -1269,7 +1319,7 @@
|
|
|
|
|
|
|
|
|
|
evt.initEvent(name, true, true); |
|
|
|
|
|
|
|
|
|
evt.to = rootEl; |
|
|
|
|
evt.to = toEl || rootEl; |
|
|
|
|
evt.from = fromEl || rootEl; |
|
|
|
|
evt.item = targetEl || rootEl; |
|
|
|
|
evt.clone = cloneEl; |
|
|
|
@ -1441,6 +1491,8 @@
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function _saveInputCheckedState(root) { |
|
|
|
|
savedInputChecked.length = 0; |
|
|
|
|
|
|
|
|
|
var inputs = root.getElementsByTagName('input'); |
|
|
|
|
var idx = inputs.length; |
|
|
|
|
|
|
|
|
@ -1450,6 +1502,14 @@
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function _nextTick(fn) { |
|
|
|
|
return setTimeout(fn, 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function _cancelNextTick(id) { |
|
|
|
|
return clearTimeout(id); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Fixed #973:
|
|
|
|
|
_on(document, 'touchmove', function (evt) { |
|
|
|
|
if (Sortable.active) { |
|
|
|
@ -1457,17 +1517,6 @@
|
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
window.addEventListener('test', null, Object.defineProperty({}, 'passive', { |
|
|
|
|
get: function () { |
|
|
|
|
captureMode = { |
|
|
|
|
capture: false, |
|
|
|
|
passive: false |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
})); |
|
|
|
|
} catch (err) {} |
|
|
|
|
|
|
|
|
|
// Export utils
|
|
|
|
|
Sortable.utils = { |
|
|
|
|
on: _on, |
|
|
|
@ -1482,7 +1531,9 @@
|
|
|
|
|
closest: _closest, |
|
|
|
|
toggleClass: _toggleClass, |
|
|
|
|
clone: _clone, |
|
|
|
|
index: _index |
|
|
|
|
index: _index, |
|
|
|
|
nextTick: _nextTick, |
|
|
|
|
cancelNextTick: _cancelNextTick |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -1497,6 +1548,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Export
|
|
|
|
|
Sortable.version = '1.5.1'; |
|
|
|
|
Sortable.version = '1.7.0'; |
|
|
|
|
return Sortable; |
|
|
|
|
}); |
|
|
|
|