Updated Sortable JS plugin
Fixes an issue in Safari that stops issues from being draggable Closes #23048
This commit is contained in:
parent
b328c78855
commit
dec4376027
|
@ -22,6 +22,7 @@ Please view this file on the master branch, on stable branches it's out of date.
|
|||
- Escape ref and path for relative links !6050 (winniehell)
|
||||
- Fixed link typo on /help/ui to Alerts section. !6915 (Sam Rose)
|
||||
- Fix filtering of milestones with quotes in title (airatshigapov)
|
||||
- Fix issue boards dragging bug in Safari
|
||||
- Refactor less readable existance checking code from CoffeeScript !6289 (jlogandavison)
|
||||
- Update mail_room and enable sentinel support to Reply By Email (!7101)
|
||||
- Add task completion status in Issues and Merge Requests tabs: "X of Y tasks completed" (!6527, @gmesalazar)
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
opacity: 1!important;
|
||||
|
||||
* {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
// !important to make sure no style can override this when dragging
|
||||
cursor: -webkit-grabbing!important;
|
||||
cursor: grabbing!important;
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
* @license MIT
|
||||
*/
|
||||
|
||||
|
||||
(function (factory) {
|
||||
(function sortableModule(factory) {
|
||||
"use strict";
|
||||
|
||||
if (typeof define === "function" && define.amd) {
|
||||
|
@ -15,15 +14,22 @@
|
|||
module.exports = factory();
|
||||
}
|
||||
else if (typeof Package !== "undefined") {
|
||||
//noinspection JSUnresolvedVariable
|
||||
Sortable = factory(); // export for Meteor.js
|
||||
}
|
||||
else {
|
||||
/* jshint sub:true */
|
||||
window["Sortable"] = factory();
|
||||
}
|
||||
})(function () {
|
||||
})(function sortableFactory() {
|
||||
"use strict";
|
||||
|
||||
if (typeof window == "undefined" || !window.document) {
|
||||
return function sortableError() {
|
||||
throw new Error("Sortable.js requires a window with a document");
|
||||
};
|
||||
}
|
||||
|
||||
var dragEl,
|
||||
parentEl,
|
||||
ghostEl,
|
||||
|
@ -33,6 +39,7 @@
|
|||
|
||||
scrollEl,
|
||||
scrollParentEl,
|
||||
scrollCustomFn,
|
||||
|
||||
lastEl,
|
||||
lastCSS,
|
||||
|
@ -42,6 +49,8 @@
|
|||
newIndex,
|
||||
|
||||
activeGroup,
|
||||
putSortable,
|
||||
|
||||
autoScroll = {},
|
||||
|
||||
tapEvt,
|
||||
|
@ -58,8 +67,15 @@
|
|||
document = win.document,
|
||||
parseInt = win.parseInt,
|
||||
|
||||
$ = win.jQuery || win.Zepto,
|
||||
Polymer = win.Polymer,
|
||||
|
||||
supportDraggable = !!('draggable' in document.createElement('div')),
|
||||
supportCssPointerEvents = (function (el) {
|
||||
// false when IE11
|
||||
if (!!navigator.userAgent.match(/Trident.*rv[ :]?11\./)) {
|
||||
return false;
|
||||
}
|
||||
el = document.createElement('x');
|
||||
el.style.cssText = 'pointer-events:auto';
|
||||
return el.style.pointerEvents === 'auto';
|
||||
|
@ -88,13 +104,17 @@
|
|||
winHeight = window.innerHeight,
|
||||
|
||||
vx,
|
||||
vy
|
||||
vy,
|
||||
|
||||
scrollOffsetX,
|
||||
scrollOffsetY
|
||||
;
|
||||
|
||||
// Delect scrollEl
|
||||
if (scrollParentEl !== rootEl) {
|
||||
scrollEl = options.scroll;
|
||||
scrollParentEl = rootEl;
|
||||
scrollCustomFn = options.scrollFn;
|
||||
|
||||
if (scrollEl === true) {
|
||||
scrollEl = rootEl;
|
||||
|
@ -136,11 +156,18 @@
|
|||
|
||||
if (el) {
|
||||
autoScroll.pid = setInterval(function () {
|
||||
scrollOffsetY = vy ? vy * speed : 0;
|
||||
scrollOffsetX = vx ? vx * speed : 0;
|
||||
|
||||
if ('function' === typeof(scrollCustomFn)) {
|
||||
return scrollCustomFn.call(_this, scrollOffsetX, scrollOffsetY, evt);
|
||||
}
|
||||
|
||||
if (el === win) {
|
||||
win.scrollTo(win.pageXOffset + vx * speed, win.pageYOffset + vy * speed);
|
||||
win.scrollTo(win.pageXOffset + scrollOffsetX, win.pageYOffset + scrollOffsetY);
|
||||
} else {
|
||||
vy && (el.scrollTop += vy * speed);
|
||||
vx && (el.scrollLeft += vx * speed);
|
||||
el.scrollTop += scrollOffsetY;
|
||||
el.scrollLeft += scrollOffsetX;
|
||||
}
|
||||
}, 24);
|
||||
}
|
||||
|
@ -149,19 +176,39 @@
|
|||
}, 30),
|
||||
|
||||
_prepareGroup = function (options) {
|
||||
var group = options.group;
|
||||
|
||||
if (!group || typeof group != 'object') {
|
||||
group = options.group = {name: group};
|
||||
function toFn(value, pull) {
|
||||
if (value === void 0 || value === true) {
|
||||
value = group.name;
|
||||
}
|
||||
|
||||
['pull', 'put'].forEach(function (key) {
|
||||
if (!(key in group)) {
|
||||
group[key] = true;
|
||||
}
|
||||
});
|
||||
if (typeof value === 'function') {
|
||||
return value;
|
||||
} else {
|
||||
return function (to, from) {
|
||||
var fromGroup = from.options.group.name;
|
||||
|
||||
options.groups = ' ' + group.name + (group.put.join ? ' ' + group.put.join(' ') : '') + ' ';
|
||||
return pull
|
||||
? value
|
||||
: value && (value.join
|
||||
? value.indexOf(fromGroup) > -1
|
||||
: (fromGroup == value)
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var group = {};
|
||||
var originalGroup = options.group;
|
||||
|
||||
if (!originalGroup || typeof originalGroup != 'object') {
|
||||
originalGroup = {name: originalGroup};
|
||||
}
|
||||
|
||||
group.name = originalGroup.name;
|
||||
group.checkPull = toFn(originalGroup.pull, true);
|
||||
group.checkPut = toFn(originalGroup.put);
|
||||
|
||||
options.group = group;
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -198,6 +245,7 @@
|
|||
draggable: /[uo]l/i.test(el.nodeName) ? 'li' : '>*',
|
||||
ghostClass: 'sortable-ghost',
|
||||
chosenClass: 'sortable-chosen',
|
||||
dragClass: 'sortable-drag',
|
||||
ignore: 'a, img',
|
||||
filter: null,
|
||||
animation: 0,
|
||||
|
@ -211,7 +259,8 @@
|
|||
forceFallback: false,
|
||||
fallbackClass: 'sortable-fallback',
|
||||
fallbackOnBody: false,
|
||||
fallbackTolerance: 0
|
||||
fallbackTolerance: 0,
|
||||
fallbackOffset: {x: 0, y: 0}
|
||||
};
|
||||
|
||||
|
||||
|
@ -224,7 +273,7 @@
|
|||
|
||||
// Bind all private methods
|
||||
for (var fn in this) {
|
||||
if (fn.charAt(0) === '_') {
|
||||
if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
|
||||
this[fn] = this[fn].bind(this);
|
||||
}
|
||||
}
|
||||
|
@ -258,7 +307,7 @@
|
|||
type = evt.type,
|
||||
touch = evt.touches && evt.touches[0],
|
||||
target = (touch || evt).target,
|
||||
originalTarget = target,
|
||||
originalTarget = evt.target.shadowRoot && evt.path[0] || target,
|
||||
filter = options.filter,
|
||||
startIndex;
|
||||
|
||||
|
@ -271,13 +320,13 @@
|
|||
return; // only left button or enabled
|
||||
}
|
||||
|
||||
target = _closest(target, options.draggable, el);
|
||||
|
||||
if (!target) {
|
||||
if (options.handle && !_closest(originalTarget, options.handle, el)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.handle && !_closest(originalTarget, options.handle, el)) {
|
||||
target = _closest(target, options.draggable, el);
|
||||
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -332,16 +381,18 @@
|
|||
this._lastX = (touch || evt).clientX;
|
||||
this._lastY = (touch || evt).clientY;
|
||||
|
||||
dragEl.style['will-change'] = 'transform';
|
||||
|
||||
dragStartFn = function () {
|
||||
// Delayed drag has been triggered
|
||||
// we can re-enable the events: touchmove/mousemove
|
||||
_this._disableDelayedDrag();
|
||||
|
||||
// Make the element draggable
|
||||
dragEl.draggable = true;
|
||||
dragEl.draggable = _this.nativeDraggable;
|
||||
|
||||
// Chosen item
|
||||
_toggleClass(dragEl, _this.options.chosenClass, true);
|
||||
_toggleClass(dragEl, options.chosenClass, true);
|
||||
|
||||
// Bind the events: dragstart/dragend
|
||||
_this._triggerDragStart(touch);
|
||||
|
@ -408,7 +459,10 @@
|
|||
|
||||
try {
|
||||
if (document.selection) {
|
||||
// Timeout neccessary for IE9
|
||||
setTimeout(function () {
|
||||
document.selection.empty();
|
||||
});
|
||||
} else {
|
||||
window.getSelection().removeAllRanges();
|
||||
}
|
||||
|
@ -418,8 +472,11 @@
|
|||
|
||||
_dragStarted: function () {
|
||||
if (rootEl && dragEl) {
|
||||
var options = this.options;
|
||||
|
||||
// Apply effect
|
||||
_toggleClass(dragEl, this.options.ghostClass, true);
|
||||
_toggleClass(dragEl, options.ghostClass, true);
|
||||
_toggleClass(dragEl, options.dragClass, false);
|
||||
|
||||
Sortable.active = this;
|
||||
|
||||
|
@ -443,12 +500,11 @@
|
|||
|
||||
var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY),
|
||||
parent = target,
|
||||
groupName = ' ' + this.options.group.name + '',
|
||||
i = touchDragOverListeners.length;
|
||||
|
||||
if (parent) {
|
||||
do {
|
||||
if (parent[expando] && parent[expando].options.groups.indexOf(groupName) > -1) {
|
||||
if (parent[expando]) {
|
||||
while (i--) {
|
||||
touchDragOverListeners[i]({
|
||||
clientX: touchEvt.clientX,
|
||||
|
@ -478,9 +534,10 @@
|
|||
if (tapEvt) {
|
||||
var options = this.options,
|
||||
fallbackTolerance = options.fallbackTolerance,
|
||||
fallbackOffset = options.fallbackOffset,
|
||||
touch = evt.touches ? evt.touches[0] : evt,
|
||||
dx = touch.clientX - tapEvt.clientX,
|
||||
dy = touch.clientY - tapEvt.clientY,
|
||||
dx = (touch.clientX - tapEvt.clientX) + fallbackOffset.x,
|
||||
dy = (touch.clientY - tapEvt.clientY) + fallbackOffset.y,
|
||||
translate3d = evt.touches ? 'translate3d(' + dx + 'px,' + dy + 'px,0)' : 'translate(' + dx + 'px,' + dy + 'px)';
|
||||
|
||||
// only set the status to dragging, when we are actually dragging
|
||||
|
@ -520,6 +577,7 @@
|
|||
|
||||
_toggleClass(ghostEl, options.ghostClass, false);
|
||||
_toggleClass(ghostEl, options.fallbackClass, true);
|
||||
_toggleClass(ghostEl, options.dragClass, true);
|
||||
|
||||
_css(ghostEl, 'top', rect.top - parseInt(css.marginTop, 10));
|
||||
_css(ghostEl, 'left', rect.left - parseInt(css.marginLeft, 10));
|
||||
|
@ -545,13 +603,15 @@
|
|||
|
||||
this._offUpEvents();
|
||||
|
||||
if (activeGroup.pull == 'clone') {
|
||||
cloneEl = dragEl.cloneNode(true);
|
||||
if (activeGroup.checkPull(this, this, dragEl, evt) == 'clone') {
|
||||
cloneEl = _clone(dragEl);
|
||||
_css(cloneEl, 'display', 'none');
|
||||
rootEl.insertBefore(cloneEl, dragEl);
|
||||
_dispatchEvent(this, rootEl, 'clone', dragEl);
|
||||
}
|
||||
|
||||
_toggleClass(dragEl, options.dragClass, true);
|
||||
|
||||
if (useFallback) {
|
||||
if (useFallback === 'touch') {
|
||||
// Bind touch events
|
||||
|
@ -581,10 +641,11 @@
|
|||
var el = this.el,
|
||||
target,
|
||||
dragRect,
|
||||
targetRect,
|
||||
revert,
|
||||
options = this.options,
|
||||
group = options.group,
|
||||
groupPut = group.put,
|
||||
activeSortable = Sortable.active,
|
||||
isOwner = (activeGroup === group),
|
||||
canSort = options.sort;
|
||||
|
||||
|
@ -598,9 +659,9 @@
|
|||
if (activeGroup && !options.disabled &&
|
||||
(isOwner
|
||||
? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list
|
||||
: activeGroup.pull && groupPut && (
|
||||
(activeGroup.name === group.name) || // by Name
|
||||
(groupPut.indexOf && ~groupPut.indexOf(activeGroup.name)) // by Array
|
||||
: (
|
||||
putSortable === this ||
|
||||
activeGroup.checkPull(this, activeSortable, dragEl, evt) && group.checkPut(this, activeSortable, dragEl, evt)
|
||||
)
|
||||
) &&
|
||||
(evt.rootEl === void 0 || evt.rootEl === this.el) // touch fallback
|
||||
|
@ -614,6 +675,7 @@
|
|||
|
||||
target = _closest(evt.target, options.draggable, el);
|
||||
dragRect = dragEl.getBoundingClientRect();
|
||||
putSortable = this;
|
||||
|
||||
if (revert) {
|
||||
_cloneHide(true);
|
||||
|
@ -633,7 +695,6 @@
|
|||
if ((el.children.length === 0) || (el.children[0] === ghostEl) ||
|
||||
(el === evt.target) && (target = _ghostIsLast(el, evt))
|
||||
) {
|
||||
|
||||
if (target) {
|
||||
if (target.animated) {
|
||||
return;
|
||||
|
@ -644,7 +705,7 @@
|
|||
|
||||
_cloneHide(isOwner);
|
||||
|
||||
if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect) !== false) {
|
||||
if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt) !== false) {
|
||||
if (!dragEl.contains(el)) {
|
||||
el.appendChild(dragEl);
|
||||
parentEl = el; // actualization
|
||||
|
@ -661,9 +722,9 @@
|
|||
lastParentCSS = _css(target.parentNode);
|
||||
}
|
||||
|
||||
targetRect = target.getBoundingClientRect();
|
||||
|
||||
var targetRect = target.getBoundingClientRect(),
|
||||
width = targetRect.right - targetRect.left,
|
||||
var width = targetRect.right - targetRect.left,
|
||||
height = targetRect.bottom - targetRect.top,
|
||||
floating = /left|right|inline/.test(lastCSS.cssFloat + lastCSS.display)
|
||||
|| (lastParentCSS.display == 'flex' && lastParentCSS['flex-direction'].indexOf('row') === 0),
|
||||
|
@ -671,7 +732,7 @@
|
|||
isLong = (target.offsetHeight > dragEl.offsetHeight),
|
||||
halfway = (floating ? (evt.clientX - targetRect.left) / width : (evt.clientY - targetRect.top) / height) > 0.5,
|
||||
nextSibling = target.nextElementSibling,
|
||||
moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect),
|
||||
moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt),
|
||||
after
|
||||
;
|
||||
|
||||
|
@ -784,6 +845,7 @@
|
|||
}
|
||||
|
||||
_disableDraggable(dragEl);
|
||||
dragEl.style['will-change'] = '';
|
||||
|
||||
// Remove class's
|
||||
_toggleClass(dragEl, this.options.ghostClass, false);
|
||||
|
@ -793,15 +855,16 @@
|
|||
newIndex = _index(dragEl, options.draggable);
|
||||
|
||||
if (newIndex >= 0) {
|
||||
// drag from one list and drop into another
|
||||
_dispatchEvent(null, parentEl, 'sort', dragEl, rootEl, oldIndex, newIndex);
|
||||
_dispatchEvent(this, rootEl, 'sort', dragEl, rootEl, oldIndex, newIndex);
|
||||
|
||||
// Add event
|
||||
_dispatchEvent(null, parentEl, 'add', dragEl, rootEl, oldIndex, newIndex);
|
||||
|
||||
// Remove event
|
||||
_dispatchEvent(this, rootEl, 'remove', dragEl, rootEl, oldIndex, newIndex);
|
||||
|
||||
// drag from one list and drop into another
|
||||
_dispatchEvent(null, parentEl, 'sort', dragEl, rootEl, oldIndex, newIndex);
|
||||
_dispatchEvent(this, rootEl, 'sort', dragEl, rootEl, oldIndex, newIndex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -821,7 +884,8 @@
|
|||
}
|
||||
|
||||
if (Sortable.active) {
|
||||
if (newIndex === null || newIndex === -1) {
|
||||
/* jshint eqnull:true */
|
||||
if (newIndex == null || newIndex === -1) {
|
||||
newIndex = oldIndex;
|
||||
}
|
||||
|
||||
|
@ -857,6 +921,7 @@
|
|||
lastEl =
|
||||
lastCSS =
|
||||
|
||||
putSortable =
|
||||
activeGroup =
|
||||
Sortable.active = null;
|
||||
},
|
||||
|
@ -1011,14 +1076,21 @@
|
|||
if ((selector === '>*' && el.parentNode === ctx) || _matches(el, selector)) {
|
||||
return el;
|
||||
}
|
||||
}
|
||||
while (el !== ctx && (el = el.parentNode));
|
||||
/* jshint boss:true */
|
||||
} while (el = _getParentOrHost(el));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
function _getParentOrHost(el) {
|
||||
var parent = el.host;
|
||||
|
||||
return (parent && parent.nodeType) ? parent : el.parentNode;
|
||||
}
|
||||
|
||||
|
||||
function _globalDragOver(/**Event*/evt) {
|
||||
if (evt.dataTransfer) {
|
||||
evt.dataTransfer.dropEffect = 'move';
|
||||
|
@ -1094,8 +1166,10 @@
|
|||
|
||||
|
||||
function _dispatchEvent(sortable, rootEl, name, targetEl, fromEl, startIndex, newIndex) {
|
||||
sortable = (sortable || rootEl[expando]);
|
||||
|
||||
var evt = document.createEvent('Event'),
|
||||
options = (sortable || rootEl[expando]).options,
|
||||
options = sortable.options,
|
||||
onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1);
|
||||
|
||||
evt.initEvent(name, true, true);
|
||||
|
@ -1116,7 +1190,7 @@
|
|||
}
|
||||
|
||||
|
||||
function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect) {
|
||||
function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvt) {
|
||||
var evt,
|
||||
sortable = fromEl[expando],
|
||||
onMoveFn = sortable.options.onMove,
|
||||
|
@ -1135,7 +1209,7 @@
|
|||
fromEl.dispatchEvent(evt);
|
||||
|
||||
if (onMoveFn) {
|
||||
retVal = onMoveFn.call(sortable, evt);
|
||||
retVal = onMoveFn.call(sortable, evt, originalEvt);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
|
@ -1157,7 +1231,12 @@
|
|||
var lastEl = el.lastElementChild,
|
||||
rect = lastEl.getBoundingClientRect();
|
||||
|
||||
return ((evt.clientY - (rect.top + rect.height) > 5) || (evt.clientX - (rect.right + rect.width) > 5)) && lastEl; // min delta
|
||||
// 5 — min delta
|
||||
// abs — нельзя добавлять, а то глюки при наведении сверху
|
||||
return (
|
||||
(evt.clientY - (rect.top + rect.height) > 5) ||
|
||||
(evt.clientX - (rect.right + rect.width) > 5)
|
||||
) && lastEl;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1251,6 +1330,15 @@
|
|||
return dst;
|
||||
}
|
||||
|
||||
function _clone(el) {
|
||||
return $
|
||||
? $(el).clone(true)[0]
|
||||
: (Polymer && Polymer.dom
|
||||
? Polymer.dom(el).cloneNode(true)
|
||||
: el.cloneNode(true)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Export utils
|
||||
Sortable.utils = {
|
||||
|
@ -1265,6 +1353,7 @@
|
|||
throttle: _throttle,
|
||||
closest: _closest,
|
||||
toggleClass: _toggleClass,
|
||||
clone: _clone,
|
||||
index: _index
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue