@pantograph/sortable 1.15.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +829 -0
- package/Sortable.js +3647 -0
- package/Sortable.min.js +2 -0
- package/modular/sortable.complete.esm.js +3639 -0
- package/modular/sortable.core.esm.js +3506 -0
- package/modular/sortable.esm.js +3637 -0
- package/package.json +57 -0
- package/src/Animation.js +175 -0
- package/src/BrowserInfo.js +12 -0
- package/src/EventDispatcher.js +57 -0
- package/src/PluginManager.js +94 -0
- package/src/Sortable.js +2099 -0
- package/src/index.d.ts +549 -0
- package/src/plugins.d.ts +117 -0
- package/src/utils.js +600 -0
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pantograph/sortable",
|
|
3
|
+
"exportName": "Sortable",
|
|
4
|
+
"version": "1.15.6",
|
|
5
|
+
"devDependencies": {
|
|
6
|
+
"@babel/core": "^7.4.4",
|
|
7
|
+
"@babel/plugin-transform-object-assign": "^7.2.0",
|
|
8
|
+
"@babel/preset-env": "^7.4.4",
|
|
9
|
+
"rollup": "^1.11.3",
|
|
10
|
+
"rollup-plugin-babel": "^4.3.2",
|
|
11
|
+
"rollup-plugin-json": "^4.0.0",
|
|
12
|
+
"rollup-plugin-node-resolve": "^5.0.0",
|
|
13
|
+
"testcafe": "^1.3.1",
|
|
14
|
+
"testcafe-browser-provider-saucelabs": "^1.7.0",
|
|
15
|
+
"testcafe-reporter-xunit": "^2.1.0",
|
|
16
|
+
"uglify-js": "^3.5.12"
|
|
17
|
+
},
|
|
18
|
+
"description": "JavaScript library for reorderable drag-and-drop lists on modern browsers and touch devices. No jQuery required. Supports Meteor, AngularJS, React, Polymer, Vue, Knockout and any CSS library, e.g. Bootstrap.",
|
|
19
|
+
"main": "./Sortable.min.js",
|
|
20
|
+
"module": "modular/sortable.esm.js",
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build:umd": "set NODE_ENV=umd&& rollup -c ./scripts/umd-build.js",
|
|
23
|
+
"build:umd:watch": "set NODE_ENV=umd&& rollup -w -c ./scripts/umd-build.js",
|
|
24
|
+
"build:es": "set NODE_ENV=es&& rollup -c ./scripts/esm-build.js",
|
|
25
|
+
"build:es:watch": "set NODE_ENV=es&& rollup -w -c ./scripts/esm-build.js",
|
|
26
|
+
"minify": "node ./scripts/minify.js",
|
|
27
|
+
"build": "npm run build:es && npm run build:umd && npm run minify",
|
|
28
|
+
"test:compat": "node ./scripts/test-compat.js",
|
|
29
|
+
"test": "node ./scripts/test.js"
|
|
30
|
+
},
|
|
31
|
+
"maintainers": [
|
|
32
|
+
"Konstantin Lebedev <ibnRubaXa@gmail.com>",
|
|
33
|
+
"Owen Mills <owen23355@gmail.com>"
|
|
34
|
+
],
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git://github.com/SortableJS/Sortable.git"
|
|
38
|
+
},
|
|
39
|
+
"files": [
|
|
40
|
+
"Sortable.js",
|
|
41
|
+
"Sortable.min.js",
|
|
42
|
+
"modular/",
|
|
43
|
+
"src/"
|
|
44
|
+
],
|
|
45
|
+
"keywords": [
|
|
46
|
+
"sortable",
|
|
47
|
+
"reorder",
|
|
48
|
+
"drag",
|
|
49
|
+
"meteor",
|
|
50
|
+
"angular",
|
|
51
|
+
"ng-sortable",
|
|
52
|
+
"react",
|
|
53
|
+
"vue",
|
|
54
|
+
"mixin"
|
|
55
|
+
],
|
|
56
|
+
"license": "MIT"
|
|
57
|
+
}
|
package/src/Animation.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { getRect, css, matrix, isRectEqual, indexOfObject } from './utils.js';
|
|
2
|
+
import Sortable from './Sortable.js';
|
|
3
|
+
|
|
4
|
+
export default function AnimationStateManager() {
|
|
5
|
+
let animationStates = [],
|
|
6
|
+
animationCallbackId;
|
|
7
|
+
|
|
8
|
+
return {
|
|
9
|
+
captureAnimationState() {
|
|
10
|
+
animationStates = [];
|
|
11
|
+
if (!this.options.animation) return;
|
|
12
|
+
let children = [].slice.call(this.el.children);
|
|
13
|
+
|
|
14
|
+
children.forEach(child => {
|
|
15
|
+
if (css(child, 'display') === 'none' || child === Sortable.ghost) return;
|
|
16
|
+
animationStates.push({
|
|
17
|
+
target: child,
|
|
18
|
+
rect: getRect(child)
|
|
19
|
+
});
|
|
20
|
+
let fromRect = { ...animationStates[animationStates.length - 1].rect };
|
|
21
|
+
|
|
22
|
+
// If animating: compensate for current animation
|
|
23
|
+
if (child.thisAnimationDuration) {
|
|
24
|
+
let childMatrix = matrix(child, true);
|
|
25
|
+
if (childMatrix) {
|
|
26
|
+
fromRect.top -= childMatrix.f;
|
|
27
|
+
fromRect.left -= childMatrix.e;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
child.fromRect = fromRect;
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
addAnimationState(state) {
|
|
36
|
+
animationStates.push(state);
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
removeAnimationState(target) {
|
|
40
|
+
animationStates.splice(indexOfObject(animationStates, { target }), 1);
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
animateAll(callback) {
|
|
44
|
+
if (!this.options.animation) {
|
|
45
|
+
clearTimeout(animationCallbackId);
|
|
46
|
+
if (typeof(callback) === 'function') callback();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let animating = false,
|
|
51
|
+
animationTime = 0;
|
|
52
|
+
|
|
53
|
+
animationStates.forEach((state) => {
|
|
54
|
+
let time = 0,
|
|
55
|
+
animatingThis = false,
|
|
56
|
+
target = state.target,
|
|
57
|
+
fromRect = target.fromRect,
|
|
58
|
+
toRect = getRect(target),
|
|
59
|
+
prevFromRect = target.prevFromRect,
|
|
60
|
+
prevToRect = target.prevToRect,
|
|
61
|
+
animatingRect = state.rect,
|
|
62
|
+
targetMatrix = matrix(target, true);
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
if (targetMatrix) {
|
|
66
|
+
// Compensate for current animation
|
|
67
|
+
toRect.top -= targetMatrix.f;
|
|
68
|
+
toRect.left -= targetMatrix.e;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
target.toRect = toRect;
|
|
72
|
+
|
|
73
|
+
if (target.thisAnimationDuration) {
|
|
74
|
+
// Could also check if animatingRect is between fromRect and toRect
|
|
75
|
+
if (
|
|
76
|
+
isRectEqual(prevFromRect, toRect) &&
|
|
77
|
+
!isRectEqual(fromRect, toRect) &&
|
|
78
|
+
// Make sure animatingRect is on line between toRect & fromRect
|
|
79
|
+
(animatingRect.top - toRect.top) /
|
|
80
|
+
(animatingRect.left - toRect.left) ===
|
|
81
|
+
(fromRect.top - toRect.top) /
|
|
82
|
+
(fromRect.left - toRect.left)
|
|
83
|
+
) {
|
|
84
|
+
// If returning to same place as started from animation and on same axis
|
|
85
|
+
time = calculateRealTime(animatingRect, prevFromRect, prevToRect, this.options);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// if fromRect != toRect: animate
|
|
90
|
+
if (!isRectEqual(toRect, fromRect)) {
|
|
91
|
+
target.prevFromRect = fromRect;
|
|
92
|
+
target.prevToRect = toRect;
|
|
93
|
+
|
|
94
|
+
if (!time) {
|
|
95
|
+
time = this.options.animation;
|
|
96
|
+
}
|
|
97
|
+
this.animate(
|
|
98
|
+
target,
|
|
99
|
+
animatingRect,
|
|
100
|
+
toRect,
|
|
101
|
+
time
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (time) {
|
|
106
|
+
animating = true;
|
|
107
|
+
animationTime = Math.max(animationTime, time);
|
|
108
|
+
clearTimeout(target.animationResetTimer);
|
|
109
|
+
target.animationResetTimer = setTimeout(function() {
|
|
110
|
+
target.animationTime = 0;
|
|
111
|
+
target.prevFromRect = null;
|
|
112
|
+
target.fromRect = null;
|
|
113
|
+
target.prevToRect = null;
|
|
114
|
+
target.thisAnimationDuration = null;
|
|
115
|
+
}, time);
|
|
116
|
+
target.thisAnimationDuration = time;
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
clearTimeout(animationCallbackId);
|
|
122
|
+
if (!animating) {
|
|
123
|
+
if (typeof(callback) === 'function') callback();
|
|
124
|
+
} else {
|
|
125
|
+
animationCallbackId = setTimeout(function() {
|
|
126
|
+
if (typeof(callback) === 'function') callback();
|
|
127
|
+
}, animationTime);
|
|
128
|
+
}
|
|
129
|
+
animationStates = [];
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
animate(target, currentRect, toRect, duration) {
|
|
133
|
+
if (duration) {
|
|
134
|
+
css(target, 'transition', '');
|
|
135
|
+
css(target, 'transform', '');
|
|
136
|
+
let elMatrix = matrix(this.el),
|
|
137
|
+
scaleX = elMatrix && elMatrix.a,
|
|
138
|
+
scaleY = elMatrix && elMatrix.d,
|
|
139
|
+
translateX = (currentRect.left - toRect.left) / (scaleX || 1),
|
|
140
|
+
translateY = (currentRect.top - toRect.top) / (scaleY || 1);
|
|
141
|
+
|
|
142
|
+
target.animatingX = !!translateX;
|
|
143
|
+
target.animatingY = !!translateY;
|
|
144
|
+
|
|
145
|
+
css(target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)');
|
|
146
|
+
|
|
147
|
+
this.forRepaintDummy = repaint(target); // repaint
|
|
148
|
+
|
|
149
|
+
css(target, 'transition', 'transform ' + duration + 'ms' + (this.options.easing ? ' ' + this.options.easing : ''));
|
|
150
|
+
css(target, 'transform', 'translate3d(0,0,0)');
|
|
151
|
+
(typeof target.animated === 'number') && clearTimeout(target.animated);
|
|
152
|
+
target.animated = setTimeout(function () {
|
|
153
|
+
css(target, 'transition', '');
|
|
154
|
+
css(target, 'transform', '');
|
|
155
|
+
target.animated = false;
|
|
156
|
+
|
|
157
|
+
target.animatingX = false;
|
|
158
|
+
target.animatingY = false;
|
|
159
|
+
}, duration);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function repaint(target) {
|
|
166
|
+
return target.offsetWidth;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
function calculateRealTime(animatingRect, fromRect, toRect, options) {
|
|
171
|
+
return (
|
|
172
|
+
Math.sqrt(Math.pow(fromRect.top - animatingRect.top, 2) + Math.pow(fromRect.left - animatingRect.left, 2)) /
|
|
173
|
+
Math.sqrt(Math.pow(fromRect.top - toRect.top, 2) + Math.pow(fromRect.left - toRect.left, 2))
|
|
174
|
+
) * options.animation;
|
|
175
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
function userAgent(pattern) {
|
|
2
|
+
if (typeof window !== 'undefined' && window.navigator) {
|
|
3
|
+
return !!/*@__PURE__*/navigator.userAgent.match(pattern);
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const IE11OrLess = userAgent(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i);
|
|
8
|
+
export const Edge = userAgent(/Edge/i);
|
|
9
|
+
export const FireFox = userAgent(/firefox/i);
|
|
10
|
+
export const Safari = userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i);
|
|
11
|
+
export const IOS = userAgent(/iP(ad|od|hone)/i);
|
|
12
|
+
export const ChromeForAndroid = userAgent(/chrome/i) && userAgent(/android/i);
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { IE11OrLess, Edge } from './BrowserInfo.js';
|
|
2
|
+
import { expando } from './utils.js';
|
|
3
|
+
import PluginManager from './PluginManager.js';
|
|
4
|
+
|
|
5
|
+
export default function dispatchEvent(
|
|
6
|
+
{
|
|
7
|
+
sortable, rootEl, name,
|
|
8
|
+
targetEl, cloneEl, toEl, fromEl,
|
|
9
|
+
oldIndex, newIndex,
|
|
10
|
+
oldDraggableIndex, newDraggableIndex,
|
|
11
|
+
originalEvent, putSortable, extraEventProperties
|
|
12
|
+
}
|
|
13
|
+
) {
|
|
14
|
+
sortable = (sortable || (rootEl && rootEl[expando]));
|
|
15
|
+
if (!sortable) return;
|
|
16
|
+
|
|
17
|
+
let evt,
|
|
18
|
+
options = sortable.options,
|
|
19
|
+
onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1);
|
|
20
|
+
// Support for new CustomEvent feature
|
|
21
|
+
if (window.CustomEvent && !IE11OrLess && !Edge) {
|
|
22
|
+
evt = new CustomEvent(name, {
|
|
23
|
+
bubbles: true,
|
|
24
|
+
cancelable: true
|
|
25
|
+
});
|
|
26
|
+
} else {
|
|
27
|
+
evt = document.createEvent('Event');
|
|
28
|
+
evt.initEvent(name, true, true);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
evt.to = toEl || rootEl;
|
|
32
|
+
evt.from = fromEl || rootEl;
|
|
33
|
+
evt.item = targetEl || rootEl;
|
|
34
|
+
evt.clone = cloneEl;
|
|
35
|
+
|
|
36
|
+
evt.oldIndex = oldIndex;
|
|
37
|
+
evt.newIndex = newIndex;
|
|
38
|
+
|
|
39
|
+
evt.oldDraggableIndex = oldDraggableIndex;
|
|
40
|
+
evt.newDraggableIndex = newDraggableIndex;
|
|
41
|
+
|
|
42
|
+
evt.originalEvent = originalEvent;
|
|
43
|
+
evt.pullMode = putSortable ? putSortable.lastPutMode : undefined;
|
|
44
|
+
|
|
45
|
+
let allEventProperties = { ...extraEventProperties, ...PluginManager.getEventProperties(name, sortable) };
|
|
46
|
+
for (let option in allEventProperties) {
|
|
47
|
+
evt[option] = allEventProperties[option];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (rootEl) {
|
|
51
|
+
rootEl.dispatchEvent(evt);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (options[onName]) {
|
|
55
|
+
options[onName].call(sortable, evt);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
let plugins = [];
|
|
2
|
+
|
|
3
|
+
const defaults = {
|
|
4
|
+
initializeByDefault: true
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
mount(plugin) {
|
|
9
|
+
// Set default static properties
|
|
10
|
+
for (let option in defaults) {
|
|
11
|
+
if (defaults.hasOwnProperty(option) && !(option in plugin)) {
|
|
12
|
+
plugin[option] = defaults[option];
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
plugins.forEach(p => {
|
|
17
|
+
if (p.pluginName === plugin.pluginName) {
|
|
18
|
+
throw (`Sortable: Cannot mount plugin ${ plugin.pluginName } more than once`);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
plugins.push(plugin);
|
|
23
|
+
},
|
|
24
|
+
pluginEvent(eventName, sortable, evt) {
|
|
25
|
+
this.eventCanceled = false;
|
|
26
|
+
evt.cancel = () => {
|
|
27
|
+
this.eventCanceled = true;
|
|
28
|
+
};
|
|
29
|
+
const eventNameGlobal = eventName + 'Global';
|
|
30
|
+
plugins.forEach(plugin => {
|
|
31
|
+
if (!sortable[plugin.pluginName]) return;
|
|
32
|
+
// Fire global events if it exists in this sortable
|
|
33
|
+
if (
|
|
34
|
+
sortable[plugin.pluginName][eventNameGlobal]
|
|
35
|
+
) {
|
|
36
|
+
sortable[plugin.pluginName][eventNameGlobal]({ sortable, ...evt });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Only fire plugin event if plugin is enabled in this sortable,
|
|
40
|
+
// and plugin has event defined
|
|
41
|
+
if (
|
|
42
|
+
sortable.options[plugin.pluginName] &&
|
|
43
|
+
sortable[plugin.pluginName][eventName]
|
|
44
|
+
) {
|
|
45
|
+
sortable[plugin.pluginName][eventName]({ sortable, ...evt });
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
},
|
|
49
|
+
initializePlugins(sortable, el, defaults, options) {
|
|
50
|
+
plugins.forEach(plugin => {
|
|
51
|
+
const pluginName = plugin.pluginName;
|
|
52
|
+
if (!sortable.options[pluginName] && !plugin.initializeByDefault) return;
|
|
53
|
+
|
|
54
|
+
let initialized = new plugin(sortable, el, sortable.options);
|
|
55
|
+
initialized.sortable = sortable;
|
|
56
|
+
initialized.options = sortable.options;
|
|
57
|
+
sortable[pluginName] = initialized;
|
|
58
|
+
|
|
59
|
+
// Add default options from plugin
|
|
60
|
+
Object.assign(defaults, initialized.defaults);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
for (let option in sortable.options) {
|
|
64
|
+
if (!sortable.options.hasOwnProperty(option)) continue;
|
|
65
|
+
let modified = this.modifyOption(sortable, option, sortable.options[option]);
|
|
66
|
+
if (typeof(modified) !== 'undefined') {
|
|
67
|
+
sortable.options[option] = modified;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
getEventProperties(name, sortable) {
|
|
72
|
+
let eventProperties = {};
|
|
73
|
+
plugins.forEach(plugin => {
|
|
74
|
+
if (typeof(plugin.eventProperties) !== 'function') return;
|
|
75
|
+
Object.assign(eventProperties, plugin.eventProperties.call(sortable[plugin.pluginName], name));
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return eventProperties;
|
|
79
|
+
},
|
|
80
|
+
modifyOption(sortable, name, value) {
|
|
81
|
+
let modifiedValue;
|
|
82
|
+
plugins.forEach(plugin => {
|
|
83
|
+
// Plugin must exist on the Sortable
|
|
84
|
+
if (!sortable[plugin.pluginName]) return;
|
|
85
|
+
|
|
86
|
+
// If static option listener exists for this option, call in the context of the Sortable's instance of this plugin
|
|
87
|
+
if (plugin.optionListeners && typeof(plugin.optionListeners[name]) === 'function') {
|
|
88
|
+
modifiedValue = plugin.optionListeners[name].call(sortable[plugin.pluginName], value);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
return modifiedValue;
|
|
93
|
+
}
|
|
94
|
+
};
|