init commit
This commit is contained in:
175
public/assets/libs/Sortable/src/Animation.js
Normal file
175
public/assets/libs/Sortable/src/Animation.js
Normal file
@@ -0,0 +1,175 @@
|
||||
import { getRect, css, matrix, isRectEqual, indexOfObject } from './utils.js';
|
||||
import Sortable from './Sortable.js';
|
||||
|
||||
export default function AnimationStateManager() {
|
||||
let animationStates = [],
|
||||
animationCallbackId;
|
||||
|
||||
return {
|
||||
captureAnimationState() {
|
||||
animationStates = [];
|
||||
if (!this.options.animation) return;
|
||||
let children = [].slice.call(this.el.children);
|
||||
|
||||
children.forEach(child => {
|
||||
if (css(child, 'display') === 'none' || child === Sortable.ghost) return;
|
||||
animationStates.push({
|
||||
target: child,
|
||||
rect: getRect(child)
|
||||
});
|
||||
let fromRect = { ...animationStates[animationStates.length - 1].rect };
|
||||
|
||||
// If animating: compensate for current animation
|
||||
if (child.thisAnimationDuration) {
|
||||
let childMatrix = matrix(child, true);
|
||||
if (childMatrix) {
|
||||
fromRect.top -= childMatrix.f;
|
||||
fromRect.left -= childMatrix.e;
|
||||
}
|
||||
}
|
||||
|
||||
child.fromRect = fromRect;
|
||||
});
|
||||
},
|
||||
|
||||
addAnimationState(state) {
|
||||
animationStates.push(state);
|
||||
},
|
||||
|
||||
removeAnimationState(target) {
|
||||
animationStates.splice(indexOfObject(animationStates, { target }), 1);
|
||||
},
|
||||
|
||||
animateAll(callback) {
|
||||
if (!this.options.animation) {
|
||||
clearTimeout(animationCallbackId);
|
||||
if (typeof(callback) === 'function') callback();
|
||||
return;
|
||||
}
|
||||
|
||||
let animating = false,
|
||||
animationTime = 0;
|
||||
|
||||
animationStates.forEach((state) => {
|
||||
let time = 0,
|
||||
animatingThis = false,
|
||||
target = state.target,
|
||||
fromRect = target.fromRect,
|
||||
toRect = getRect(target),
|
||||
prevFromRect = target.prevFromRect,
|
||||
prevToRect = target.prevToRect,
|
||||
animatingRect = state.rect,
|
||||
targetMatrix = matrix(target, true);
|
||||
|
||||
|
||||
if (targetMatrix) {
|
||||
// Compensate for current animation
|
||||
toRect.top -= targetMatrix.f;
|
||||
toRect.left -= targetMatrix.e;
|
||||
}
|
||||
|
||||
target.toRect = toRect;
|
||||
|
||||
if (target.thisAnimationDuration) {
|
||||
// Could also check if animatingRect is between fromRect and toRect
|
||||
if (
|
||||
isRectEqual(prevFromRect, toRect) &&
|
||||
!isRectEqual(fromRect, toRect) &&
|
||||
// Make sure animatingRect is on line between toRect & fromRect
|
||||
(animatingRect.top - toRect.top) /
|
||||
(animatingRect.left - toRect.left) ===
|
||||
(fromRect.top - toRect.top) /
|
||||
(fromRect.left - toRect.left)
|
||||
) {
|
||||
// If returning to same place as started from animation and on same axis
|
||||
time = calculateRealTime(animatingRect, prevFromRect, prevToRect, this.options);
|
||||
}
|
||||
}
|
||||
|
||||
// if fromRect != toRect: animate
|
||||
if (!isRectEqual(toRect, fromRect)) {
|
||||
target.prevFromRect = fromRect;
|
||||
target.prevToRect = toRect;
|
||||
|
||||
if (!time) {
|
||||
time = this.options.animation;
|
||||
}
|
||||
this.animate(
|
||||
target,
|
||||
animatingRect,
|
||||
toRect,
|
||||
time
|
||||
);
|
||||
}
|
||||
|
||||
if (time) {
|
||||
animating = true;
|
||||
animationTime = Math.max(animationTime, time);
|
||||
clearTimeout(target.animationResetTimer);
|
||||
target.animationResetTimer = setTimeout(function() {
|
||||
target.animationTime = 0;
|
||||
target.prevFromRect = null;
|
||||
target.fromRect = null;
|
||||
target.prevToRect = null;
|
||||
target.thisAnimationDuration = null;
|
||||
}, time);
|
||||
target.thisAnimationDuration = time;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
clearTimeout(animationCallbackId);
|
||||
if (!animating) {
|
||||
if (typeof(callback) === 'function') callback();
|
||||
} else {
|
||||
animationCallbackId = setTimeout(function() {
|
||||
if (typeof(callback) === 'function') callback();
|
||||
}, animationTime);
|
||||
}
|
||||
animationStates = [];
|
||||
},
|
||||
|
||||
animate(target, currentRect, toRect, duration) {
|
||||
if (duration) {
|
||||
css(target, 'transition', '');
|
||||
css(target, 'transform', '');
|
||||
let elMatrix = matrix(this.el),
|
||||
scaleX = elMatrix && elMatrix.a,
|
||||
scaleY = elMatrix && elMatrix.d,
|
||||
translateX = (currentRect.left - toRect.left) / (scaleX || 1),
|
||||
translateY = (currentRect.top - toRect.top) / (scaleY || 1);
|
||||
|
||||
target.animatingX = !!translateX;
|
||||
target.animatingY = !!translateY;
|
||||
|
||||
css(target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)');
|
||||
|
||||
repaint(target); // repaint
|
||||
|
||||
css(target, 'transition', 'transform ' + duration + 'ms' + (this.options.easing ? ' ' + this.options.easing : ''));
|
||||
css(target, 'transform', 'translate3d(0,0,0)');
|
||||
(typeof target.animated === 'number') && clearTimeout(target.animated);
|
||||
target.animated = setTimeout(function () {
|
||||
css(target, 'transition', '');
|
||||
css(target, 'transform', '');
|
||||
target.animated = false;
|
||||
|
||||
target.animatingX = false;
|
||||
target.animatingY = false;
|
||||
}, duration);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function repaint(target) {
|
||||
return target.offsetWidth;
|
||||
}
|
||||
|
||||
|
||||
function calculateRealTime(animatingRect, fromRect, toRect, options) {
|
||||
return (
|
||||
Math.sqrt(Math.pow(fromRect.top - animatingRect.top, 2) + Math.pow(fromRect.left - animatingRect.left, 2)) /
|
||||
Math.sqrt(Math.pow(fromRect.top - toRect.top, 2) + Math.pow(fromRect.left - toRect.left, 2))
|
||||
) * options.animation;
|
||||
}
|
||||
12
public/assets/libs/Sortable/src/BrowserInfo.js
Normal file
12
public/assets/libs/Sortable/src/BrowserInfo.js
Normal file
@@ -0,0 +1,12 @@
|
||||
function userAgent(pattern) {
|
||||
if (typeof window !== 'undefined' && window.navigator) {
|
||||
return !!/*@__PURE__*/navigator.userAgent.match(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
export const IE11OrLess = userAgent(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i);
|
||||
export const Edge = userAgent(/Edge/i);
|
||||
export const FireFox = userAgent(/firefox/i);
|
||||
export const Safari = userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i);
|
||||
export const IOS = userAgent(/iP(ad|od|hone)/i);
|
||||
export const ChromeForAndroid = userAgent(/chrome/i) && userAgent(/android/i);
|
||||
57
public/assets/libs/Sortable/src/EventDispatcher.js
Normal file
57
public/assets/libs/Sortable/src/EventDispatcher.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import { IE11OrLess, Edge } from './BrowserInfo.js';
|
||||
import { expando } from './utils.js';
|
||||
import PluginManager from './PluginManager.js';
|
||||
|
||||
export default function dispatchEvent(
|
||||
{
|
||||
sortable, rootEl, name,
|
||||
targetEl, cloneEl, toEl, fromEl,
|
||||
oldIndex, newIndex,
|
||||
oldDraggableIndex, newDraggableIndex,
|
||||
originalEvent, putSortable, extraEventProperties
|
||||
}
|
||||
) {
|
||||
sortable = (sortable || (rootEl && rootEl[expando]));
|
||||
if (!sortable) return;
|
||||
|
||||
let evt,
|
||||
options = sortable.options,
|
||||
onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1);
|
||||
// Support for new CustomEvent feature
|
||||
if (window.CustomEvent && !IE11OrLess && !Edge) {
|
||||
evt = new CustomEvent(name, {
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
});
|
||||
} else {
|
||||
evt = document.createEvent('Event');
|
||||
evt.initEvent(name, true, true);
|
||||
}
|
||||
|
||||
evt.to = toEl || rootEl;
|
||||
evt.from = fromEl || rootEl;
|
||||
evt.item = targetEl || rootEl;
|
||||
evt.clone = cloneEl;
|
||||
|
||||
evt.oldIndex = oldIndex;
|
||||
evt.newIndex = newIndex;
|
||||
|
||||
evt.oldDraggableIndex = oldDraggableIndex;
|
||||
evt.newDraggableIndex = newDraggableIndex;
|
||||
|
||||
evt.originalEvent = originalEvent;
|
||||
evt.pullMode = putSortable ? putSortable.lastPutMode : undefined;
|
||||
|
||||
let allEventProperties = { ...extraEventProperties, ...PluginManager.getEventProperties(name, sortable) };
|
||||
for (let option in allEventProperties) {
|
||||
evt[option] = allEventProperties[option];
|
||||
}
|
||||
|
||||
if (rootEl) {
|
||||
rootEl.dispatchEvent(evt);
|
||||
}
|
||||
|
||||
if (options[onName]) {
|
||||
options[onName].call(sortable, evt);
|
||||
}
|
||||
}
|
||||
87
public/assets/libs/Sortable/src/PluginManager.js
Normal file
87
public/assets/libs/Sortable/src/PluginManager.js
Normal file
@@ -0,0 +1,87 @@
|
||||
let plugins = [];
|
||||
|
||||
const defaults = {
|
||||
initializeByDefault: true
|
||||
};
|
||||
|
||||
export default {
|
||||
mount(plugin) {
|
||||
// Set default static properties
|
||||
for (let option in defaults) {
|
||||
if (defaults.hasOwnProperty(option) && !(option in plugin)) {
|
||||
plugin[option] = defaults[option];
|
||||
}
|
||||
}
|
||||
plugins.push(plugin);
|
||||
},
|
||||
pluginEvent(eventName, sortable, evt) {
|
||||
this.eventCanceled = false;
|
||||
evt.cancel = () => {
|
||||
this.eventCanceled = true;
|
||||
};
|
||||
const eventNameGlobal = eventName + 'Global';
|
||||
plugins.forEach(plugin => {
|
||||
if (!sortable[plugin.pluginName]) return;
|
||||
// Fire global events if it exists in this sortable
|
||||
if (
|
||||
sortable[plugin.pluginName][eventNameGlobal]
|
||||
) {
|
||||
sortable[plugin.pluginName][eventNameGlobal]({ sortable, ...evt });
|
||||
}
|
||||
|
||||
// Only fire plugin event if plugin is enabled in this sortable,
|
||||
// and plugin has event defined
|
||||
if (
|
||||
sortable.options[plugin.pluginName] &&
|
||||
sortable[plugin.pluginName][eventName]
|
||||
) {
|
||||
sortable[plugin.pluginName][eventName]({ sortable, ...evt });
|
||||
}
|
||||
});
|
||||
},
|
||||
initializePlugins(sortable, el, defaults, options) {
|
||||
plugins.forEach(plugin => {
|
||||
const pluginName = plugin.pluginName;
|
||||
if (!sortable.options[pluginName] && !plugin.initializeByDefault) return;
|
||||
|
||||
let initialized = new plugin(sortable, el, sortable.options);
|
||||
initialized.sortable = sortable;
|
||||
initialized.options = sortable.options;
|
||||
sortable[pluginName] = initialized;
|
||||
|
||||
// Add default options from plugin
|
||||
Object.assign(defaults, initialized.defaults);
|
||||
});
|
||||
|
||||
for (let option in sortable.options) {
|
||||
if (!sortable.options.hasOwnProperty(option)) continue;
|
||||
let modified = this.modifyOption(sortable, option, sortable.options[option]);
|
||||
if (typeof(modified) !== 'undefined') {
|
||||
sortable.options[option] = modified;
|
||||
}
|
||||
}
|
||||
},
|
||||
getEventProperties(name, sortable) {
|
||||
let eventProperties = {};
|
||||
plugins.forEach(plugin => {
|
||||
if (typeof(plugin.eventProperties) !== 'function') return;
|
||||
Object.assign(eventProperties, plugin.eventProperties.call(sortable[plugin.pluginName], name));
|
||||
});
|
||||
|
||||
return eventProperties;
|
||||
},
|
||||
modifyOption(sortable, name, value) {
|
||||
let modifiedValue;
|
||||
plugins.forEach(plugin => {
|
||||
// Plugin must exist on the Sortable
|
||||
if (!sortable[plugin.pluginName]) return;
|
||||
|
||||
// If static option listener exists for this option, call in the context of the Sortable's instance of this plugin
|
||||
if (plugin.optionListeners && typeof(plugin.optionListeners[name]) === 'function') {
|
||||
modifiedValue = plugin.optionListeners[name].call(sortable[plugin.pluginName], value);
|
||||
}
|
||||
});
|
||||
|
||||
return modifiedValue;
|
||||
}
|
||||
};
|
||||
1966
public/assets/libs/Sortable/src/Sortable.js
Normal file
1966
public/assets/libs/Sortable/src/Sortable.js
Normal file
File diff suppressed because it is too large
Load Diff
556
public/assets/libs/Sortable/src/utils.js
Normal file
556
public/assets/libs/Sortable/src/utils.js
Normal file
@@ -0,0 +1,556 @@
|
||||
import { IE11OrLess } from './BrowserInfo.js';
|
||||
import Sortable from './Sortable.js';
|
||||
|
||||
const captureMode = {
|
||||
capture: false,
|
||||
passive: false
|
||||
};
|
||||
|
||||
function on(el, event, fn) {
|
||||
el.addEventListener(event, fn, !IE11OrLess && captureMode);
|
||||
}
|
||||
|
||||
|
||||
function off(el, event, fn) {
|
||||
el.removeEventListener(event, fn, !IE11OrLess && captureMode);
|
||||
}
|
||||
|
||||
function matches(/**HTMLElement*/el, /**String*/selector) {
|
||||
if (!selector) return;
|
||||
|
||||
selector[0] === '>' && (selector = selector.substring(1));
|
||||
|
||||
if (el) {
|
||||
try {
|
||||
if (el.matches) {
|
||||
return el.matches(selector);
|
||||
} else if (el.msMatchesSelector) {
|
||||
return el.msMatchesSelector(selector);
|
||||
} else if (el.webkitMatchesSelector) {
|
||||
return el.webkitMatchesSelector(selector);
|
||||
}
|
||||
} catch(_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getParentOrHost(el) {
|
||||
return (el.host && el !== document && el.host.nodeType)
|
||||
? el.host
|
||||
: el.parentNode;
|
||||
}
|
||||
|
||||
function closest(/**HTMLElement*/el, /**String*/selector, /**HTMLElement*/ctx, includeCTX) {
|
||||
if (el) {
|
||||
ctx = ctx || document;
|
||||
|
||||
do {
|
||||
if (
|
||||
selector != null &&
|
||||
(
|
||||
selector[0] === '>' ?
|
||||
el.parentNode === ctx && matches(el, selector) :
|
||||
matches(el, selector)
|
||||
) ||
|
||||
includeCTX && el === ctx
|
||||
) {
|
||||
return el;
|
||||
}
|
||||
|
||||
if (el === ctx) break;
|
||||
/* jshint boss:true */
|
||||
} while (el = getParentOrHost(el));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const R_SPACE = /\s+/g;
|
||||
|
||||
function toggleClass(el, name, state) {
|
||||
if (el && name) {
|
||||
if (el.classList) {
|
||||
el.classList[state ? 'add' : 'remove'](name);
|
||||
}
|
||||
else {
|
||||
let className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' ');
|
||||
el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function css(el, prop, val) {
|
||||
let style = el && el.style;
|
||||
|
||||
if (style) {
|
||||
if (val === void 0) {
|
||||
if (document.defaultView && document.defaultView.getComputedStyle) {
|
||||
val = document.defaultView.getComputedStyle(el, '');
|
||||
}
|
||||
else if (el.currentStyle) {
|
||||
val = el.currentStyle;
|
||||
}
|
||||
|
||||
return prop === void 0 ? val : val[prop];
|
||||
}
|
||||
else {
|
||||
if (!(prop in style) && prop.indexOf('webkit') === -1) {
|
||||
prop = '-webkit-' + prop;
|
||||
}
|
||||
|
||||
style[prop] = val + (typeof val === 'string' ? '' : 'px');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function matrix(el, selfOnly) {
|
||||
let appliedTransforms = '';
|
||||
if (typeof(el) === 'string') {
|
||||
appliedTransforms = el;
|
||||
} else {
|
||||
do {
|
||||
let transform = css(el, 'transform');
|
||||
|
||||
if (transform && transform !== 'none') {
|
||||
appliedTransforms = transform + ' ' + appliedTransforms;
|
||||
}
|
||||
/* jshint boss:true */
|
||||
} while (!selfOnly && (el = el.parentNode));
|
||||
}
|
||||
|
||||
const matrixFn = window.DOMMatrix || window.WebKitCSSMatrix || window.CSSMatrix || window.MSCSSMatrix;
|
||||
/*jshint -W056 */
|
||||
return matrixFn && (new matrixFn(appliedTransforms));
|
||||
}
|
||||
|
||||
|
||||
function find(ctx, tagName, iterator) {
|
||||
if (ctx) {
|
||||
let list = ctx.getElementsByTagName(tagName), i = 0, n = list.length;
|
||||
|
||||
if (iterator) {
|
||||
for (; i < n; i++) {
|
||||
iterator(list[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getWindowScrollingElement() {
|
||||
let scrollingElement = document.scrollingElement;
|
||||
|
||||
if (scrollingElement) {
|
||||
return scrollingElement
|
||||
} else {
|
||||
return document.documentElement
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the "bounding client rect" of given element
|
||||
* @param {HTMLElement} el The element whose boundingClientRect is wanted
|
||||
* @param {[Boolean]} relativeToContainingBlock Whether the rect should be relative to the containing block of (including) the container
|
||||
* @param {[Boolean]} relativeToNonStaticParent Whether the rect should be relative to the relative parent of (including) the contaienr
|
||||
* @param {[Boolean]} undoScale Whether the container's scale() should be undone
|
||||
* @param {[HTMLElement]} container The parent the element will be placed in
|
||||
* @return {Object} The boundingClientRect of el, with specified adjustments
|
||||
*/
|
||||
function getRect(el, relativeToContainingBlock, relativeToNonStaticParent, undoScale, container) {
|
||||
if (!el.getBoundingClientRect && el !== window) return;
|
||||
|
||||
let elRect,
|
||||
top,
|
||||
left,
|
||||
bottom,
|
||||
right,
|
||||
height,
|
||||
width;
|
||||
|
||||
if (el !== window && el !== getWindowScrollingElement()) {
|
||||
elRect = el.getBoundingClientRect();
|
||||
top = elRect.top;
|
||||
left = elRect.left;
|
||||
bottom = elRect.bottom;
|
||||
right = elRect.right;
|
||||
height = elRect.height;
|
||||
width = elRect.width;
|
||||
} else {
|
||||
top = 0;
|
||||
left = 0;
|
||||
bottom = window.innerHeight;
|
||||
right = window.innerWidth;
|
||||
height = window.innerHeight;
|
||||
width = window.innerWidth;
|
||||
}
|
||||
|
||||
if ((relativeToContainingBlock || relativeToNonStaticParent) && el !== window) {
|
||||
// Adjust for translate()
|
||||
container = container || el.parentNode;
|
||||
|
||||
// solves #1123 (see: https://stackoverflow.com/a/37953806/6088312)
|
||||
// Not needed on <= IE11
|
||||
if (!IE11OrLess) {
|
||||
do {
|
||||
if (
|
||||
container &&
|
||||
container.getBoundingClientRect &&
|
||||
(
|
||||
css(container, 'transform') !== 'none' ||
|
||||
relativeToNonStaticParent &&
|
||||
css(container, 'position') !== 'static'
|
||||
)
|
||||
) {
|
||||
let containerRect = container.getBoundingClientRect();
|
||||
|
||||
// Set relative to edges of padding box of container
|
||||
top -= containerRect.top + parseInt(css(container, 'border-top-width'));
|
||||
left -= containerRect.left + parseInt(css(container, 'border-left-width'));
|
||||
bottom = top + elRect.height;
|
||||
right = left + elRect.width;
|
||||
|
||||
break;
|
||||
}
|
||||
/* jshint boss:true */
|
||||
} while (container = container.parentNode);
|
||||
}
|
||||
}
|
||||
|
||||
if (undoScale && el !== window) {
|
||||
// Adjust for scale()
|
||||
let elMatrix = matrix(container || el),
|
||||
scaleX = elMatrix && elMatrix.a,
|
||||
scaleY = elMatrix && elMatrix.d;
|
||||
|
||||
if (elMatrix) {
|
||||
top /= scaleY;
|
||||
left /= scaleX;
|
||||
|
||||
width /= scaleX;
|
||||
height /= scaleY;
|
||||
|
||||
bottom = top + height;
|
||||
right = left + width;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
top: top,
|
||||
left: left,
|
||||
bottom: bottom,
|
||||
right: right,
|
||||
width: width,
|
||||
height: height
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a side of an element is scrolled past a side of its parents
|
||||
* @param {HTMLElement} el The element who's side being scrolled out of view is in question
|
||||
* @param {String} elSide Side of the element in question ('top', 'left', 'right', 'bottom')
|
||||
* @param {String} parentSide Side of the parent in question ('top', 'left', 'right', 'bottom')
|
||||
* @return {HTMLElement} The parent scroll element that the el's side is scrolled past, or null if there is no such element
|
||||
*/
|
||||
function isScrolledPast(el, elSide, parentSide) {
|
||||
let parent = getParentAutoScrollElement(el, true),
|
||||
elSideVal = getRect(el)[elSide];
|
||||
|
||||
/* jshint boss:true */
|
||||
while (parent) {
|
||||
let parentSideVal = getRect(parent)[parentSide],
|
||||
visible;
|
||||
|
||||
if (parentSide === 'top' || parentSide === 'left') {
|
||||
visible = elSideVal >= parentSideVal;
|
||||
} else {
|
||||
visible = elSideVal <= parentSideVal;
|
||||
}
|
||||
|
||||
if (!visible) return parent;
|
||||
|
||||
if (parent === getWindowScrollingElement()) break;
|
||||
|
||||
parent = getParentAutoScrollElement(parent, false);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets nth child of el, ignoring hidden children, sortable's elements (does not ignore clone if it's visible)
|
||||
* and non-draggable elements
|
||||
* @param {HTMLElement} el The parent element
|
||||
* @param {Number} childNum The index of the child
|
||||
* @param {Object} options Parent Sortable's options
|
||||
* @return {HTMLElement} The child at index childNum, or null if not found
|
||||
*/
|
||||
function getChild(el, childNum, options) {
|
||||
let currentChild = 0,
|
||||
i = 0,
|
||||
children = el.children;
|
||||
|
||||
while (i < children.length) {
|
||||
if (
|
||||
children[i].style.display !== 'none' &&
|
||||
children[i] !== Sortable.ghost &&
|
||||
children[i] !== Sortable.dragged &&
|
||||
closest(children[i], options.draggable, el, false)
|
||||
) {
|
||||
if (currentChild === childNum) {
|
||||
return children[i];
|
||||
}
|
||||
currentChild++;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last child in the el, ignoring ghostEl or invisible elements (clones)
|
||||
* @param {HTMLElement} el Parent element
|
||||
* @param {selector} selector Any other elements that should be ignored
|
||||
* @return {HTMLElement} The last child, ignoring ghostEl
|
||||
*/
|
||||
function lastChild(el, selector) {
|
||||
let last = el.lastElementChild;
|
||||
|
||||
while (
|
||||
last &&
|
||||
(
|
||||
last === Sortable.ghost ||
|
||||
css(last, 'display') === 'none' ||
|
||||
selector && !matches(last, selector)
|
||||
)
|
||||
) {
|
||||
last = last.previousElementSibling;
|
||||
}
|
||||
|
||||
return last || null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the index of an element within its parent for a selected set of
|
||||
* elements
|
||||
* @param {HTMLElement} el
|
||||
* @param {selector} selector
|
||||
* @return {number}
|
||||
*/
|
||||
function index(el, selector) {
|
||||
let index = 0;
|
||||
|
||||
if (!el || !el.parentNode) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* jshint boss:true */
|
||||
while (el = el.previousElementSibling) {
|
||||
if ((el.nodeName.toUpperCase() !== 'TEMPLATE') && el !== Sortable.clone && (!selector || matches(el, selector))) {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the scroll offset of the given element, added with all the scroll offsets of parent elements.
|
||||
* The value is returned in real pixels.
|
||||
* @param {HTMLElement} el
|
||||
* @return {Array} Offsets in the format of [left, top]
|
||||
*/
|
||||
function getRelativeScrollOffset(el) {
|
||||
let offsetLeft = 0,
|
||||
offsetTop = 0,
|
||||
winScroller = getWindowScrollingElement();
|
||||
|
||||
if (el) {
|
||||
do {
|
||||
let elMatrix = matrix(el),
|
||||
scaleX = elMatrix.a,
|
||||
scaleY = elMatrix.d;
|
||||
|
||||
offsetLeft += el.scrollLeft * scaleX;
|
||||
offsetTop += el.scrollTop * scaleY;
|
||||
} while (el !== winScroller && (el = el.parentNode));
|
||||
}
|
||||
|
||||
return [offsetLeft, offsetTop];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the object within the given array
|
||||
* @param {Array} arr Array that may or may not hold the object
|
||||
* @param {Object} obj An object that has a key-value pair unique to and identical to a key-value pair in the object you want to find
|
||||
* @return {Number} The index of the object in the array, or -1
|
||||
*/
|
||||
function indexOfObject(arr, obj) {
|
||||
for (let i in arr) {
|
||||
if (!arr.hasOwnProperty(i)) continue;
|
||||
for (let key in obj) {
|
||||
if (obj.hasOwnProperty(key) && obj[key] === arr[i][key]) return Number(i);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
function getParentAutoScrollElement(el, includeSelf) {
|
||||
// skip to window
|
||||
if (!el || !el.getBoundingClientRect) return getWindowScrollingElement();
|
||||
|
||||
let elem = el;
|
||||
let gotSelf = false;
|
||||
do {
|
||||
// we don't need to get elem css if it isn't even overflowing in the first place (performance)
|
||||
if (elem.clientWidth < elem.scrollWidth || elem.clientHeight < elem.scrollHeight) {
|
||||
let elemCSS = css(elem);
|
||||
if (
|
||||
elem.clientWidth < elem.scrollWidth && (elemCSS.overflowX == 'auto' || elemCSS.overflowX == 'scroll') ||
|
||||
elem.clientHeight < elem.scrollHeight && (elemCSS.overflowY == 'auto' || elemCSS.overflowY == 'scroll')
|
||||
) {
|
||||
if (!elem.getBoundingClientRect || elem === document.body) return getWindowScrollingElement();
|
||||
|
||||
if (gotSelf || includeSelf) return elem;
|
||||
gotSelf = true;
|
||||
}
|
||||
}
|
||||
/* jshint boss:true */
|
||||
} while (elem = elem.parentNode);
|
||||
|
||||
return getWindowScrollingElement();
|
||||
}
|
||||
|
||||
function extend(dst, src) {
|
||||
if (dst && src) {
|
||||
for (let key in src) {
|
||||
if (src.hasOwnProperty(key)) {
|
||||
dst[key] = src[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
function isRectEqual(rect1, rect2) {
|
||||
return Math.round(rect1.top) === Math.round(rect2.top) &&
|
||||
Math.round(rect1.left) === Math.round(rect2.left) &&
|
||||
Math.round(rect1.height) === Math.round(rect2.height) &&
|
||||
Math.round(rect1.width) === Math.round(rect2.width);
|
||||
}
|
||||
|
||||
|
||||
let _throttleTimeout;
|
||||
function throttle(callback, ms) {
|
||||
return function () {
|
||||
if (!_throttleTimeout) {
|
||||
let args = arguments,
|
||||
_this = this;
|
||||
|
||||
if (args.length === 1) {
|
||||
callback.call(_this, args[0]);
|
||||
} else {
|
||||
callback.apply(_this, args);
|
||||
}
|
||||
|
||||
_throttleTimeout = setTimeout(function () {
|
||||
_throttleTimeout = void 0;
|
||||
}, ms);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function cancelThrottle() {
|
||||
clearTimeout(_throttleTimeout);
|
||||
_throttleTimeout = void 0;
|
||||
}
|
||||
|
||||
|
||||
function scrollBy(el, x, y) {
|
||||
el.scrollLeft += x;
|
||||
el.scrollTop += y;
|
||||
}
|
||||
|
||||
|
||||
function clone(el) {
|
||||
let Polymer = window.Polymer;
|
||||
let $ = window.jQuery || window.Zepto;
|
||||
|
||||
if (Polymer && Polymer.dom) {
|
||||
return Polymer.dom(el).cloneNode(true);
|
||||
}
|
||||
else if ($) {
|
||||
return $(el).clone(true)[0];
|
||||
}
|
||||
else {
|
||||
return el.cloneNode(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function setRect(el, rect) {
|
||||
css(el, 'position', 'absolute');
|
||||
css(el, 'top', rect.top);
|
||||
css(el, 'left', rect.left);
|
||||
css(el, 'width', rect.width);
|
||||
css(el, 'height', rect.height);
|
||||
}
|
||||
|
||||
function unsetRect(el) {
|
||||
css(el, 'position', '');
|
||||
css(el, 'top', '');
|
||||
css(el, 'left', '');
|
||||
css(el, 'width', '');
|
||||
css(el, 'height', '');
|
||||
}
|
||||
|
||||
|
||||
const expando = 'Sortable' + (new Date).getTime();
|
||||
|
||||
|
||||
export {
|
||||
on,
|
||||
off,
|
||||
matches,
|
||||
getParentOrHost,
|
||||
closest,
|
||||
toggleClass,
|
||||
css,
|
||||
matrix,
|
||||
find,
|
||||
getWindowScrollingElement,
|
||||
getRect,
|
||||
isScrolledPast,
|
||||
getChild,
|
||||
lastChild,
|
||||
index,
|
||||
getRelativeScrollOffset,
|
||||
indexOfObject,
|
||||
getParentAutoScrollElement,
|
||||
extend,
|
||||
isRectEqual,
|
||||
throttle,
|
||||
cancelThrottle,
|
||||
scrollBy,
|
||||
clone,
|
||||
setRect,
|
||||
unsetRect,
|
||||
expando
|
||||
};
|
||||
Reference in New Issue
Block a user