draggable-rails 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/lib/draggable/rails/version.rb +1 -1
  3. data/vendor/assets/javascripts/behaviour/collidable.js +99 -0
  4. data/vendor/assets/javascripts/behaviour/snappable.js +107 -0
  5. data/vendor/assets/javascripts/core/accessibility.js +58 -0
  6. data/vendor/assets/javascripts/core/mirror.js +129 -0
  7. data/vendor/assets/javascripts/draggable.js +487 -0
  8. data/vendor/assets/javascripts/droppable.js +168 -0
  9. data/vendor/assets/javascripts/events/abstract-event.js +45 -0
  10. data/vendor/assets/javascripts/events/collidable-event.js +25 -0
  11. data/vendor/assets/javascripts/events/drag-event.js +91 -0
  12. data/vendor/assets/javascripts/events/draggable-event.js +17 -0
  13. data/vendor/assets/javascripts/events/droppable-event.js +21 -0
  14. data/vendor/assets/javascripts/events/mirror-event.js +43 -0
  15. data/vendor/assets/javascripts/events/sensor-event.js +47 -0
  16. data/vendor/assets/javascripts/events/snappable-event.js +15 -0
  17. data/vendor/assets/javascripts/events/sortable-event.js +35 -0
  18. data/vendor/assets/javascripts/events/swappable-event.js +23 -0
  19. data/vendor/assets/javascripts/index.js +18 -0
  20. data/vendor/assets/javascripts/sensors/drag-sensor.js +158 -0
  21. data/vendor/assets/javascripts/sensors/force-touch-sensor.js +166 -0
  22. data/vendor/assets/javascripts/sensors/mouse-sensor.js +110 -0
  23. data/vendor/assets/javascripts/sensors/sensor.js +23 -0
  24. data/vendor/assets/javascripts/sensors/touch-sensor.js +145 -0
  25. data/vendor/assets/javascripts/sortable.js +161 -0
  26. data/vendor/assets/javascripts/swappable.js +104 -0
  27. data/vendor/assets/javascripts/utils.js +52 -0
  28. metadata +26 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1a9c0fb9461722b2c3faf25b8630e900c2f22d8e
4
- data.tar.gz: a2c1018ccfc626a6d6757401c9bc70007352ff55
3
+ metadata.gz: 8ca6434b4515d382cf869565d05835704455c6d7
4
+ data.tar.gz: 76116c2095b2282b6f29b0ad987466c72582da6b
5
5
  SHA512:
6
- metadata.gz: 893c37beeafa5c194fa862c08dd989720f23576349980d86cda78d38b80bfec2fab6139b0f9e7d3391f2c33d67f13f8a2b50f536977a2bfd9e01301f81ac1d03
7
- data.tar.gz: b281790116a02f5c394ee8a7aac79c3dd9784468b31696c8f3d3b51813e842fb50d759b93b1f5ced3dc4d7f739b4ad7cebe5696a3bf4171a4c5f16c994280eb3
6
+ metadata.gz: 6d7800084b1fa71f466f93a8cece89c9c52c84dea9b5d8f4f81cf8bc1d7ba270f9cc72915c2b82a6a437d49f9130ded5191bf9199883d840610ba8a827e5ecc1
7
+ data.tar.gz: 14482cd176bd243dd63cff18650ae4e88ad62f377bc8ad63b9577cf44ac893c70a06b26e7bb26efbc0981c2325227d7bb7e6bb23ad01023a6c7fa12fd7fa219e
@@ -1,5 +1,5 @@
1
1
  module Draggable
2
2
  module Rails
3
- VERSION = "0.1.0"
3
+ VERSION = "0.1.1"
4
4
  end
5
5
  end
@@ -0,0 +1,99 @@
1
+ import {closest} from './../utils';
2
+
3
+ import {
4
+ CollidableInEvent,
5
+ CollidableOutEvent,
6
+ } from './../events/collidable-event';
7
+
8
+ export default class Collidable {
9
+ constructor(draggable) {
10
+ this.draggable = draggable;
11
+
12
+ this._onDragMove = this._onDragMove.bind(this);
13
+ this._onDragStop = this._onDragStop.bind(this);
14
+ this._onRequestAnimationFrame = this._onRequestAnimationFrame.bind(this);
15
+ }
16
+
17
+ attach() {
18
+ this.draggable.on('drag:move', this._onDragMove);
19
+ this.draggable.on('drag:stop', this._onDragStop);
20
+ }
21
+
22
+ detach() {
23
+ this.draggable.off('drag:move', this._onDragMove);
24
+ this.draggable.off('drag:stop', this._onDragStop);
25
+ }
26
+
27
+ _onDragMove(event) {
28
+ const target = event.sensorEvent.target;
29
+
30
+ this.currentAnimationFrame = requestAnimationFrame(this._onRequestAnimationFrame(target));
31
+
32
+ if (this.currentlyCollidingElement) {
33
+ event.cancel();
34
+ }
35
+
36
+ const collidableInEvent = new CollidableInEvent({
37
+ dragEvent: event,
38
+ collidingElement: this.currentlyCollidingElement,
39
+ });
40
+
41
+ const collidableOutEvent = new CollidableOutEvent({
42
+ dragEvent: event,
43
+ collidingElement: this.lastCollidingElement,
44
+ });
45
+
46
+ const enteringCollidable = Boolean(this.currentlyCollidingElement && this.lastCollidingElement !== this.currentlyCollidingElement);
47
+ const leavingCollidable = Boolean(!this.currentlyCollidingElement && this.lastCollidingElement);
48
+
49
+ if (enteringCollidable) {
50
+ if (this.lastCollidingElement) {
51
+ this.draggable.triggerEvent(collidableOutEvent);
52
+ }
53
+
54
+ this.draggable.triggerEvent(collidableInEvent);
55
+ } else if (leavingCollidable) {
56
+ this.draggable.triggerEvent(collidableOutEvent);
57
+ }
58
+
59
+ this.lastCollidingElement = this.currentlyCollidingElement;
60
+ }
61
+
62
+ _onDragStop(event) {
63
+ const lastCollidingElement = this.currentlyCollidingElement || this.lastCollidingElement;
64
+ const collidableOutEvent = new CollidableOutEvent({
65
+ dragEvent: event,
66
+ collidingElement: lastCollidingElement,
67
+ });
68
+
69
+ if (lastCollidingElement) {
70
+ this.draggable.triggerEvent(collidableOutEvent);
71
+ }
72
+
73
+ this.lastCollidingElement = null;
74
+ this.currentlyCollidingElement = null;
75
+ }
76
+
77
+ _onRequestAnimationFrame(target) {
78
+ return () => {
79
+ const collidables = this._getCollidables();
80
+ this.currentlyCollidingElement = closest(target, (element) => collidables.includes(element));
81
+ };
82
+ }
83
+
84
+ _getCollidables() {
85
+ const collidables = this.draggable.options.collidables;
86
+
87
+ if (typeof collidables === 'string') {
88
+ return Array.prototype.slice.call(document.querySelectorAll(collidables));
89
+ } else if (collidables instanceof NodeList || collidables instanceof Array) {
90
+ return Array.prototype.slice.call(collidables);
91
+ } else if (collidables instanceof HTMLElement) {
92
+ return [collidables];
93
+ } else if (typeof collidables === 'function') {
94
+ return collidables();
95
+ } else {
96
+ return [];
97
+ }
98
+ }
99
+ }
@@ -0,0 +1,107 @@
1
+ import {
2
+ SnapInEvent,
3
+ SnapOutEvent,
4
+ } from './../events/snappable-event';
5
+
6
+ export default class Snappable {
7
+ constructor(draggable) {
8
+ this.draggable = draggable;
9
+
10
+ this._onDragStart = this._onDragStart.bind(this);
11
+ this._onDragStop = this._onDragStop.bind(this);
12
+ this._onDragOver = this._onDragOver.bind(this);
13
+ this._onDragOut = this._onDragOut.bind(this);
14
+ }
15
+
16
+ attach() {
17
+ this.draggable
18
+ .on('drag:start', this._onDragStart)
19
+ .on('drag:stop', this._onDragStop)
20
+ .on('drag:over', this._onDragOver)
21
+ .on('drag:out', this._onDragOut)
22
+ .on('droppable:over', this._onDragOver)
23
+ .on('droppable:out', this._onDragOut);
24
+ }
25
+
26
+ detach() {
27
+ this.draggable
28
+ .off('drag:start', this._onDragStart)
29
+ .off('drag:stop', this._onDragStop)
30
+ .off('drag:over', this._onDragOver)
31
+ .off('drag:out', this._onDragOut)
32
+ .off('droppable:over', this._onDragOver)
33
+ .off('droppable:out', this._onDragOut);
34
+ }
35
+
36
+ _onDragStart(event) {
37
+ if (event.canceled()) {
38
+ return;
39
+ }
40
+
41
+ this.firstSource = event.source;
42
+ }
43
+
44
+ _onDragStop() {
45
+ this.firstSource = null;
46
+ }
47
+
48
+ _onDragOver(event) {
49
+ if (event.canceled()) {
50
+ return;
51
+ }
52
+
53
+ const source = event.source || event.dragEvent.source;
54
+ const mirror = event.mirror || event.dragEvent.mirror;
55
+
56
+ if (source === this.firstSource) {
57
+ this.firstSource = null;
58
+ return;
59
+ }
60
+
61
+ const snapInEvent = new SnapInEvent({
62
+ dragEvent: event,
63
+ });
64
+
65
+ this.draggable.triggerEvent(snapInEvent);
66
+
67
+ if (snapInEvent.canceled()) {
68
+ return;
69
+ }
70
+
71
+ if (mirror) {
72
+ mirror.style.display = 'none';
73
+ }
74
+
75
+ source.classList.remove(this.draggable.getClassNameFor('source:dragging'));
76
+ source.classList.add(this.draggable.getClassNameFor('source:placed'));
77
+
78
+ setTimeout(() => {
79
+ source.classList.remove(this.draggable.getClassNameFor('source:placed'));
80
+ }, this.draggable.options.placedTimeout);
81
+ }
82
+
83
+ _onDragOut(event) {
84
+ if (event.canceled()) {
85
+ return;
86
+ }
87
+
88
+ const mirror = event.mirror || event.dragEvent.mirror;
89
+ const source = event.source || event.dragEvent.source;
90
+
91
+ const snapOutEvent = new SnapOutEvent({
92
+ dragEvent: event,
93
+ });
94
+
95
+ this.draggable.triggerEvent(snapOutEvent);
96
+
97
+ if (snapOutEvent.canceled()) {
98
+ return;
99
+ }
100
+
101
+ if (mirror) {
102
+ mirror.style.display = '';
103
+ }
104
+
105
+ source.classList.add(this.draggable.getClassNameFor('source:dragging'));
106
+ }
107
+ }
@@ -0,0 +1,58 @@
1
+ const ARIA_GRABBED = 'aria-grabbed';
2
+ const ARIA_DROPEFFECT = 'aria-dropeffect';
3
+ const TABINDEX = 'tabindex';
4
+
5
+ export default class Accessibility {
6
+ constructor(draggable) {
7
+ this.draggable = draggable;
8
+
9
+ this._onInit = this._onInit.bind(this);
10
+ this._onDestroy = this._onDestroy.bind(this);
11
+ }
12
+
13
+ attach() {
14
+ this.draggable
15
+ .on('init', this._onInit)
16
+ .on('destroy', this._onDestroy)
17
+ .on('drag:start', _onDragStart)
18
+ .on('drag:stop', _onDragStop);
19
+ }
20
+
21
+ detach() {
22
+ this.draggable
23
+ .off('init', this._onInit)
24
+ .off('destroy', this._onDestroy)
25
+ .off('drag:start', _onDragStart)
26
+ .off('drag:stop', _onDragStop);
27
+ }
28
+
29
+ _onInit({containers}) {
30
+ for (const container of containers) {
31
+ container.setAttribute(ARIA_DROPEFFECT, this.draggable.options.type);
32
+
33
+ for (const element of container.querySelectorAll(this.draggable.options.draggable)) {
34
+ element.setAttribute(TABINDEX, 0);
35
+ element.setAttribute(ARIA_GRABBED, false);
36
+ }
37
+ }
38
+ }
39
+
40
+ _onDestroy({containers}) {
41
+ for (const container of containers) {
42
+ container.removeAttribute(ARIA_DROPEFFECT);
43
+
44
+ for (const element of container.querySelectorAll(this.draggable.options.draggable)) {
45
+ element.removeAttribute(TABINDEX, 0);
46
+ element.removeAttribute(ARIA_GRABBED, false);
47
+ }
48
+ }
49
+ }
50
+ }
51
+
52
+ function _onDragStart({source}) {
53
+ source.setAttribute(ARIA_GRABBED, true);
54
+ }
55
+
56
+ function _onDragStop({source}) {
57
+ source.setAttribute(ARIA_GRABBED, false);
58
+ }
@@ -0,0 +1,129 @@
1
+ export default class Mirror {
2
+ constructor(draggable) {
3
+ this.draggable = draggable;
4
+
5
+ this._onMirrorCreated = this._onMirrorCreated.bind(this);
6
+ this._onMirrorMove = this._onMirrorMove.bind(this);
7
+ }
8
+
9
+ attach() {
10
+ this.draggable
11
+ .on('mirror:created', this._onMirrorCreated)
12
+ .on('mirror:created', onMirrorCreated)
13
+ .on('mirror:move', this._onMirrorMove);
14
+ }
15
+
16
+ detach() {
17
+ this.draggable
18
+ .off('mirror:created', this._onMirrorCreated)
19
+ .off('mirror:created', onMirrorCreated)
20
+ .off('mirror:move', this._onMirrorMove);
21
+ }
22
+
23
+ _onMirrorCreated({mirror, source, sensorEvent}) {
24
+ const mirrorClass = this.draggable.getClassNameFor('mirror');
25
+
26
+ const setState = (data) => {
27
+ this.mirrorOffset = data.mirrorOffset;
28
+ return data;
29
+ };
30
+
31
+ Promise.resolve({mirror, source, sensorEvent, mirrorClass})
32
+ .then(computeMirrorDimensions)
33
+ .then(calculateMirrorOffset)
34
+ .then(addMirrorClasses)
35
+ .then(positionMirror())
36
+ .then(removeMirrorID)
37
+ .then(setState)
38
+ .catch();
39
+ }
40
+
41
+ _onMirrorMove({mirror, sensorEvent}) {
42
+ Promise.resolve({mirror, sensorEvent, mirrorOffset: this.mirrorOffset})
43
+ .then(positionMirror({raf: true}))
44
+ .catch();
45
+ }
46
+ }
47
+
48
+ function onMirrorCreated({mirror, source}) {
49
+ Promise.resolve({mirror, source})
50
+ .then(resetMirror)
51
+ .catch();
52
+ }
53
+
54
+ function resetMirror(data) {
55
+ return withPromise((resolve) => {
56
+ const {mirror, source} = data;
57
+
58
+ mirror.style.position = 'fixed';
59
+ mirror.style.pointerEvents = 'none';
60
+ mirror.style.top = 0;
61
+ mirror.style.left = 0;
62
+ mirror.style.width = `${source.offsetWidth}px`;
63
+ mirror.style.height = `${source.offsetHeight}px`;
64
+
65
+ resolve(data);
66
+ });
67
+ }
68
+
69
+ function computeMirrorDimensions(data) {
70
+ return withPromise((resolve) => {
71
+ const {source} = data;
72
+ const sourceRect = source.getBoundingClientRect();
73
+ resolve({...data, sourceRect});
74
+ });
75
+ }
76
+
77
+ function calculateMirrorOffset(data) {
78
+ return withPromise((resolve) => {
79
+ const {sensorEvent, sourceRect} = data;
80
+ const mirrorOffset = {top: sensorEvent.clientY - sourceRect.top, left: sensorEvent.clientX - sourceRect.left};
81
+ resolve({...data, mirrorOffset});
82
+ });
83
+ }
84
+
85
+ function addMirrorClasses(data) {
86
+ return withPromise((resolve) => {
87
+ const {mirror, mirrorClass} = data;
88
+ mirror.classList.add(mirrorClass);
89
+ resolve(data);
90
+ });
91
+ }
92
+
93
+ function removeMirrorID(data) {
94
+ return withPromise((resolve) => {
95
+ const {mirror} = data;
96
+ mirror.removeAttribute('id');
97
+ delete mirror.id;
98
+ resolve(data);
99
+ });
100
+ }
101
+
102
+ function positionMirror({withFrame = false} = {}) {
103
+ return (data) => {
104
+ return withPromise((resolve) => {
105
+ const {mirror, sensorEvent, mirrorOffset} = data;
106
+
107
+ if (mirrorOffset) {
108
+ const x = sensorEvent.clientX - mirrorOffset.left;
109
+ const y = sensorEvent.clientY - mirrorOffset.top;
110
+
111
+ mirror.style.transform = `translate3d(${x}px, ${y}px, 0)`;
112
+ }
113
+
114
+ resolve(data);
115
+ }, {frame: withFrame});
116
+ };
117
+ }
118
+
119
+ function withPromise(callback, {raf = false} = {}) {
120
+ return new Promise((resolve, reject) => {
121
+ if (raf) {
122
+ requestAnimationFrame(() => {
123
+ callback(resolve, reject);
124
+ });
125
+ } else {
126
+ callback(resolve, reject);
127
+ }
128
+ });
129
+ }
@@ -0,0 +1,487 @@
1
+ import {closest} from './utils';
2
+
3
+ import Accessibility from './core/accessibility';
4
+ import Mirror from './core/mirror';
5
+
6
+ import Collidable from './behaviour/collidable';
7
+ import Snappable from './behaviour/snappable';
8
+
9
+ import DragSensor from './sensors/drag-sensor';
10
+ import MouseSensor from './sensors/mouse-sensor';
11
+ import TouchSensor from './sensors/touch-sensor';
12
+ import ForceTouchSensor from './sensors/force-touch-sensor';
13
+
14
+ import {
15
+ DraggableInitializedEvent,
16
+ DraggableDestroyEvent,
17
+ } from './events/draggable-event';
18
+
19
+ import {
20
+ DragStartEvent,
21
+ DragMoveEvent,
22
+ DragOutContainerEvent,
23
+ DragOutEvent,
24
+ DragOverContainerEvent,
25
+ DragOverEvent,
26
+ DragStopEvent,
27
+ DragPressureEvent,
28
+ } from './events/drag-event';
29
+
30
+ import {
31
+ MirrorCreatedEvent,
32
+ MirrorAttachedEvent,
33
+ MirrorMoveEvent,
34
+ MirrorDestroyEvent,
35
+ } from './events/mirror-event';
36
+
37
+ const defaults = {
38
+ draggable: '.draggable-source',
39
+ handle: null,
40
+ delay: 0,
41
+ placedTimeout: 800,
42
+ native: false,
43
+ plugins: [Mirror, Accessibility],
44
+ classes: {
45
+ 'container:dragging': 'draggable-container--is-dragging',
46
+ 'source:dragging': 'draggable-source--is-dragging',
47
+ 'source:placed': 'draggable-source--placed',
48
+ 'container:placed': 'draggable-container--placed',
49
+ 'body:dragging': 'draggable--is-dragging',
50
+ 'draggable:over': 'draggable--over',
51
+ 'container:over': 'draggable-container--over',
52
+ mirror: 'draggable-mirror',
53
+ },
54
+ };
55
+
56
+ /**
57
+ * This is the core draggable library that does the heavy lifting
58
+ * @module Draggable
59
+ */
60
+ export default class Draggable {
61
+ static get Plugins() {
62
+ return {Accessibility, Mirror};
63
+ }
64
+
65
+ static get Behaviour() {
66
+ return {Collidable, Snappable};
67
+ }
68
+
69
+ /**
70
+ * Draggable constructor.
71
+ * @constructs Draggable
72
+ * @param {Array|NodeList} containers - Draggable containers
73
+ * @param {Object} options - Options for draggable
74
+ */
75
+ constructor(containers = [], options = {}) {
76
+ this.containers = containers;
77
+ this.options = Object.assign({}, defaults, options);
78
+ this.activeSensors = [];
79
+ this.activePlugins = [];
80
+ this.callbacks = {};
81
+ this.dragging = false;
82
+
83
+ this.dragStart = this.dragStart.bind(this);
84
+ this.dragMove = this.dragMove.bind(this);
85
+ this.dragStop = this.dragStop.bind(this);
86
+ this.dragPressure = this.dragPressure.bind(this);
87
+
88
+ for (const container of this.containers) {
89
+ container.addEventListener('drag:start', this.dragStart, true);
90
+ container.addEventListener('drag:move', this.dragMove, true);
91
+ container.addEventListener('drag:stop', this.dragStop, true);
92
+ container.addEventListener('drag:pressure', this.dragPressure, true);
93
+ }
94
+
95
+ for (const Plugin of this.options.plugins) {
96
+ const plugin = new Plugin(this);
97
+ plugin.attach();
98
+ this.activePlugins.push(plugin);
99
+ }
100
+
101
+ for (const Sensor of this.sensors()) {
102
+ const sensor = new Sensor(this.containers, options);
103
+ sensor.attach();
104
+ this.activeSensors.push(sensor);
105
+ }
106
+
107
+ const draggableInitializedEvent = new DraggableInitializedEvent({
108
+ draggable: this,
109
+ });
110
+
111
+ this.triggerEvent(draggableInitializedEvent);
112
+ }
113
+
114
+ /**
115
+ * Destroys Draggable instance. This removes all internal event listeners and
116
+ * deactivates sensors and plugins
117
+ */
118
+ destroy() {
119
+ for (const container of this.containers) {
120
+ container.removeEventListener('drag:start', this.dragStart, true);
121
+ container.removeEventListener('drag:move', this.dragMove, true);
122
+ container.removeEventListener('drag:stop', this.dragStop, true);
123
+ container.removeEventListener('drag:pressure', this.dragPressure, true);
124
+ }
125
+
126
+ const draggableDestroyEvent = new DraggableDestroyEvent({
127
+ draggable: this,
128
+ });
129
+
130
+ this.triggerEvent(draggableDestroyEvent);
131
+
132
+ for (const activePlugin of this.activePlugins) {
133
+ activePlugin.detach();
134
+ }
135
+
136
+ for (const activeSensor of this.activeSensors) {
137
+ activeSensor.detach();
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Adds listener for draggable events
143
+ * @example draggable.on('drag:start', (dragEvent) => dragEvent.cancel());
144
+ */
145
+ on(type, callback) {
146
+ if (!this.callbacks[type]) {
147
+ this.callbacks[type] = [];
148
+ }
149
+
150
+ this.callbacks[type].push(callback);
151
+ return this;
152
+ }
153
+
154
+ /**
155
+ * Removes listener from draggable
156
+ * @example draggable.off('drag:start', handlerFunction);
157
+ */
158
+ off(type, callback) {
159
+ if (!this.callbacks[type]) { return null; }
160
+ const copy = this.callbacks[type].slice(0);
161
+ for (let i = 0; i < copy.length; i++) {
162
+ if (callback === copy[i]) {
163
+ this.callbacks[type].splice(i, 1);
164
+ }
165
+ }
166
+ return this;
167
+ }
168
+
169
+ trigger(type, ...args) {
170
+ if (!this.callbacks[type]) { return; }
171
+ for (let i = this.callbacks[type].length - 1; i >= 0; i--) {
172
+ const callback = this.callbacks[type][i];
173
+ callback(...args);
174
+ }
175
+ }
176
+
177
+ /**
178
+ * Active sensors
179
+ * @return {Array} sensors
180
+ */
181
+ sensors() {
182
+ return [
183
+ TouchSensor,
184
+ ForceTouchSensor,
185
+ (this.options.native ? DragSensor : MouseSensor),
186
+ ];
187
+ }
188
+
189
+ dragStart(event) {
190
+ const sensorEvent = getSensorEvent(event);
191
+ const {target, container, originalEvent} = sensorEvent;
192
+
193
+ if (this.options.handle && target && !closest(target, this.options.handle)) {
194
+ sensorEvent.cancel();
195
+ return;
196
+ }
197
+
198
+ // Find draggable source element
199
+ this.source = closest(target, this.options.draggable);
200
+ this.sourceContainer = container;
201
+
202
+ if (!this.source) {
203
+ sensorEvent.cancel();
204
+ return;
205
+ }
206
+
207
+ this.dragging = true;
208
+
209
+ if (!isDragEvent(originalEvent)) {
210
+ const appendableContainer = this.getAppendableContainer({source: this.source});
211
+ this.mirror = this.source.cloneNode(true);
212
+
213
+ const mirrorCreatedEvent = new MirrorCreatedEvent({
214
+ source: this.source,
215
+ mirror: this.mirror,
216
+ sourceContainer: container,
217
+ sensorEvent,
218
+ });
219
+
220
+ const mirrorAttachedEvent = new MirrorAttachedEvent({
221
+ source: this.source,
222
+ mirror: this.mirror,
223
+ sourceContainer: container,
224
+ sensorEvent,
225
+ });
226
+
227
+ this.triggerEvent(mirrorCreatedEvent);
228
+ appendableContainer.appendChild(this.mirror);
229
+ this.triggerEvent(mirrorAttachedEvent);
230
+ }
231
+
232
+ this.source.classList.add(this.getClassNameFor('source:dragging'));
233
+ this.sourceContainer.classList.add(this.getClassNameFor('container:dragging'));
234
+ document.body.classList.add(this.getClassNameFor('body:dragging'));
235
+
236
+ if (this.mirror) {
237
+ const mirrorMoveEvent = new MirrorMoveEvent({
238
+ source: this.source,
239
+ mirror: this.mirror,
240
+ sourceContainer: container,
241
+ sensorEvent,
242
+ });
243
+
244
+ this.triggerEvent(mirrorMoveEvent);
245
+ }
246
+
247
+ // Find the closest scrollable parent
248
+ this.scrollableParent = closest(container, (element) => element.offsetHeight < element.scrollHeight);
249
+
250
+ const dragEvent = new DragStartEvent({
251
+ source: this.source,
252
+ mirror: this.mirror,
253
+ sourceContainer: container,
254
+ sensorEvent,
255
+ });
256
+
257
+ this.triggerEvent(dragEvent);
258
+
259
+ if (!dragEvent.canceled()) {
260
+ return;
261
+ }
262
+
263
+ if (this.mirror) {
264
+ this.mirror.parentNode.removeChild(this.mirror);
265
+ }
266
+
267
+ this.source.classList.remove(this.getClassNameFor('source:dragging'));
268
+ this.sourceContainer.classList.remove(this.getClassNameFor('container:dragging'));
269
+ document.body.classList.remove(this.getClassNameFor('body:dragging'));
270
+ }
271
+
272
+ triggerEvent(event) {
273
+ return this.trigger(event.type, event);
274
+ }
275
+
276
+ dragMove(event) {
277
+ const sensorEvent = getSensorEvent(event);
278
+ const {container} = sensorEvent;
279
+ let target = sensorEvent.target;
280
+
281
+ const dragMoveEvent = new DragMoveEvent({
282
+ source: this.source,
283
+ mirror: this.mirror,
284
+ sourceContainer: container,
285
+ sensorEvent,
286
+ });
287
+
288
+ this.triggerEvent(dragMoveEvent);
289
+
290
+ if (dragMoveEvent.canceled()) {
291
+ sensorEvent.cancel();
292
+ }
293
+
294
+ if (this.mirror && !dragMoveEvent.canceled()) {
295
+ const mirrorMoveEvent = new MirrorMoveEvent({
296
+ source: this.source,
297
+ mirror: this.mirror,
298
+ sourceContainer: container,
299
+ sensorEvent,
300
+ });
301
+
302
+ this.triggerEvent(mirrorMoveEvent);
303
+ }
304
+
305
+ target = closest(target, this.options.draggable);
306
+ const overContainer = sensorEvent.overContainer || this.closestContainer(sensorEvent.target);
307
+ const isLeavingContainer = this.currentOverContainer && (overContainer !== this.currentOverContainer);
308
+ const isLeavingDraggable = this.currentOver && (target !== this.currentOver);
309
+ const isOverContainer = overContainer && (this.currentOverContainer !== overContainer);
310
+ const isOverDraggable = target && (this.currentOver !== target);
311
+
312
+ if (isLeavingDraggable) {
313
+ const dragOutEvent = new DragOutEvent({
314
+ source: this.source,
315
+ mirror: this.mirror,
316
+ sourceContainer: container,
317
+ sensorEvent,
318
+ over: this.currentOver,
319
+ });
320
+
321
+ this.triggerEvent(dragOutEvent);
322
+
323
+ this.currentOver.classList.remove(this.getClassNameFor('draggable:over'));
324
+ this.currentOver = null;
325
+ }
326
+
327
+ if (isLeavingContainer) {
328
+ const dragOutContainerEvent = new DragOutContainerEvent({
329
+ source: this.source,
330
+ mirror: this.mirror,
331
+ sourceContainer: container,
332
+ sensorEvent,
333
+ overContainer: this.overContainer,
334
+ });
335
+
336
+ this.triggerEvent(dragOutContainerEvent);
337
+
338
+ this.currentOverContainer.classList.remove(this.getClassNameFor('container:over'));
339
+ this.currentOverContainer = null;
340
+ }
341
+
342
+ if (isOverContainer) {
343
+ overContainer.classList.add(this.getClassNameFor('container:over'));
344
+
345
+ const dragOverContainerEvent = new DragOverContainerEvent({
346
+ source: this.source,
347
+ mirror: this.mirror,
348
+ sourceContainer: container,
349
+ sensorEvent,
350
+ overContainer,
351
+ });
352
+
353
+ this.triggerEvent(dragOverContainerEvent);
354
+
355
+ this.currentOverContainer = overContainer;
356
+ }
357
+
358
+ if (isOverDraggable) {
359
+ target.classList.add(this.getClassNameFor('draggable:over'));
360
+
361
+ const dragOverEvent = new DragOverEvent({
362
+ source: this.source,
363
+ mirror: this.mirror,
364
+ sourceContainer: container,
365
+ sensorEvent,
366
+ overContainer,
367
+ over: target,
368
+ });
369
+
370
+ this.triggerEvent(dragOverEvent);
371
+
372
+ this.currentOver = target;
373
+ }
374
+ }
375
+
376
+ dragStop(event) {
377
+ this.dragging = false;
378
+
379
+ const sensorEvent = getSensorEvent(event);
380
+ const dragStopEvent = new DragStopEvent({
381
+ source: this.source,
382
+ mirror: this.mirror,
383
+ sensorEvent: event.sensorEvent,
384
+ sourceContainer: this.sourceContainer,
385
+ });
386
+
387
+ this.triggerEvent(dragStopEvent);
388
+
389
+ this.source.classList.remove(this.getClassNameFor('source:dragging'));
390
+ this.source.classList.add(this.getClassNameFor('source:placed'));
391
+ this.sourceContainer.classList.add(this.getClassNameFor('container:placed'));
392
+ this.sourceContainer.classList.remove(this.getClassNameFor('container:dragging'));
393
+ document.body.classList.remove(this.getClassNameFor('body:dragging'));
394
+
395
+ if (this.currentOver) {
396
+ this.currentOver.classList.remove(this.getClassNameFor('draggable:over'));
397
+ }
398
+
399
+ if (this.currentOverContainer) {
400
+ this.currentOverContainer.classList.remove(this.getClassNameFor('container:over'));
401
+ }
402
+
403
+ if (this.mirror) {
404
+ const mirrorDestroyEvent = new MirrorDestroyEvent({
405
+ source: this.source,
406
+ mirror: this.mirror,
407
+ sourceContainer: sensorEvent.container,
408
+ sensorEvent,
409
+ });
410
+
411
+ this.triggerEvent(mirrorDestroyEvent);
412
+
413
+ if (!mirrorDestroyEvent.canceled()) {
414
+ this.mirror.parentNode.removeChild(this.mirror);
415
+ }
416
+ }
417
+
418
+ const lastSource = this.source;
419
+ const lastSourceContainer = this.sourceContainer;
420
+
421
+ setTimeout(() => {
422
+ if (lastSource) {
423
+ lastSource.classList.remove(this.getClassNameFor('source:placed'));
424
+ }
425
+
426
+ if (lastSourceContainer) {
427
+ lastSourceContainer.classList.remove(this.getClassNameFor('container:placed'));
428
+ }
429
+ }, this.options.placedTimeout);
430
+
431
+ this.source = null;
432
+ this.mirror = null;
433
+ this.currentOverContainer = null;
434
+ this.currentOver = null;
435
+ this.sourceContainer = null;
436
+ }
437
+
438
+ dragPressure(event) {
439
+ const sensorEvent = getSensorEvent(event);
440
+ const source = this.source || closest(sensorEvent.originalEvent.target, this.options.draggable);
441
+
442
+ const dragPressureEvent = new DragPressureEvent({
443
+ sensorEvent,
444
+ source,
445
+ pressure: sensorEvent.pressure,
446
+ });
447
+
448
+ this.triggerEvent(dragPressureEvent);
449
+ }
450
+
451
+ getAppendableContainer({source}) {
452
+ const appendTo = this.options.appendTo;
453
+
454
+ if (typeof appendTo === 'string') {
455
+ return document.querySelector(appendTo);
456
+ } else if (appendTo instanceof HTMLElement) {
457
+ return appendTo;
458
+ } else if (typeof appendTo === 'function') {
459
+ return appendTo(source);
460
+ } else {
461
+ return document.body;
462
+ }
463
+ }
464
+
465
+ getClassNameFor(name) {
466
+ return this.options.classes[name] || defaults.classes[name];
467
+ }
468
+
469
+ closestContainer(target) {
470
+ return closest(target, (element) => {
471
+ for (const containerEl of this.containers) {
472
+ if (element === containerEl) {
473
+ return true;
474
+ }
475
+ }
476
+ return false;
477
+ });
478
+ }
479
+ }
480
+
481
+ function getSensorEvent(event) {
482
+ return event.detail;
483
+ }
484
+
485
+ function isDragEvent(event) {
486
+ return /^drag/.test(event.type);
487
+ }