draggable-rails 0.1.0 → 0.1.1

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.
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
+ }