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
@@ -0,0 +1,168 @@
1
+ import Draggable from './draggable';
2
+ import {closest} from './utils';
3
+
4
+ import {
5
+ DroppableOverEvent,
6
+ DroppableOutEvent,
7
+ } from './events/droppable-event';
8
+
9
+ const classes = {
10
+ 'droppable:active': 'draggable-droppable--active',
11
+ 'droppable:occupied': 'draggable-droppable--occupied',
12
+ };
13
+
14
+ export default class Droppable {
15
+ constructor(containers = [], options = {}) {
16
+ this.draggable = new Draggable(containers, options);
17
+ this.options = {...options};
18
+
19
+ this._onDragStart = this._onDragStart.bind(this);
20
+ this._onDragMove = this._onDragMove.bind(this);
21
+ this._onDragStop = this._onDragStop.bind(this);
22
+
23
+ this.draggable
24
+ .on('drag:start', this._onDragStart)
25
+ .on('drag:move', this._onDragMove)
26
+ .on('drag:stop', this._onDragStop);
27
+ }
28
+
29
+ destroy() {
30
+ this.draggable
31
+ .off('drag:start', this._onDragStart)
32
+ .off('drag:move', this._onDragMove)
33
+ .off('drag:stop', this._onDragStop)
34
+ .destroy();
35
+ }
36
+
37
+ on(type, callback) {
38
+ this.draggable.on(type, callback);
39
+ return this;
40
+ }
41
+
42
+ off(type, callback) {
43
+ this.draggable.off(type, callback);
44
+ return this;
45
+ }
46
+
47
+ getClassNameFor(name) {
48
+ return this.options.classes[name] || classes[name];
49
+ }
50
+
51
+ _onDragStart(event) {
52
+ if (event.canceled()) {
53
+ return;
54
+ }
55
+
56
+ this.droppables = this._getDroppables();
57
+ const droppable = event.sensorEvent.target.closest(this.options.droppable);
58
+
59
+ if (!droppable) {
60
+ event.cancel();
61
+ return;
62
+ }
63
+
64
+ this.initialDroppable = droppable;
65
+
66
+ for (const droppableElement of this.droppables) {
67
+ if (droppableElement.classList.contains(this.getClassNameFor('droppable:occupied'))) {
68
+ continue;
69
+ }
70
+
71
+ droppableElement.classList.add(this.getClassNameFor('droppable:active'));
72
+ }
73
+ }
74
+
75
+ _onDragMove(event) {
76
+ if (event.canceled()) {
77
+ return;
78
+ }
79
+
80
+ const droppable = this._closestDroppable(event.sensorEvent.target);
81
+ const overEmptyDroppable = droppable && !droppable.classList.contains(this.getClassNameFor('droppable:occupied'));
82
+
83
+ if (overEmptyDroppable && this._drop(event, droppable)) {
84
+ this.lastDroppable = droppable;
85
+ } else if ((!droppable || droppable === this.initialDroppable) && this.lastDroppable) {
86
+ this._release(event);
87
+ this.lastDroppable = null;
88
+ }
89
+ }
90
+
91
+ _onDragStop() {
92
+ const occupiedClass = this.getClassNameFor('droppable:occupied');
93
+
94
+ for (const droppable of this.droppables) {
95
+ droppable.classList.remove(this.getClassNameFor('droppable:active'));
96
+ }
97
+
98
+ if (this.lastDroppable && this.lastDroppable !== this.initialDroppable) {
99
+ this.initialDroppable.classList.remove(occupiedClass);
100
+ }
101
+
102
+ this.droppables = null;
103
+ this.lastDroppable = null;
104
+ this.initialDroppable = null;
105
+ }
106
+
107
+ _drop(event, droppable) {
108
+ const droppableOverEvent = new DroppableOverEvent({
109
+ dragEvent: event,
110
+ droppable,
111
+ });
112
+
113
+ this.draggable.triggerEvent(droppableOverEvent);
114
+
115
+ if (droppableOverEvent.canceled()) {
116
+ return false;
117
+ }
118
+
119
+ const occupiedClass = this.getClassNameFor('droppable:occupied');
120
+
121
+ if (this.lastDroppable) {
122
+ this.lastDroppable.classList.remove(occupiedClass);
123
+ }
124
+
125
+ droppable.appendChild(event.source);
126
+ droppable.classList.add(occupiedClass);
127
+
128
+ return true;
129
+ }
130
+
131
+ _release(event) {
132
+ const droppableOutEvent = new DroppableOutEvent({
133
+ dragEvent: event,
134
+ droppable: this.lastDroppable,
135
+ });
136
+
137
+ this.draggable.triggerEvent(droppableOutEvent);
138
+
139
+ if (droppableOutEvent.canceled()) {
140
+ return;
141
+ }
142
+
143
+ this.initialDroppable.appendChild(event.source);
144
+ this.lastDroppable.classList.remove(this.getClassNameFor('droppable:occupied'));
145
+ }
146
+
147
+ _closestDroppable(target) {
148
+ if (!this.droppables) {
149
+ return null;
150
+ }
151
+
152
+ return closest(target, (element) => Array.from(this.droppables).includes(element));
153
+ }
154
+
155
+ _getDroppables() {
156
+ const droppables = this.options.droppable;
157
+
158
+ if (typeof droppables === 'string') {
159
+ return document.querySelectorAll(droppables);
160
+ } else if (droppables instanceof NodeList || droppables instanceof Array) {
161
+ return droppables;
162
+ } else if (typeof droppables === 'function') {
163
+ return droppables();
164
+ } else {
165
+ return [];
166
+ }
167
+ }
168
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * All events fired by draggable inherit this class. You can call `cancel()` to
3
+ * cancel a specific event or you can check if an event has been canceled by
4
+ * calling `canceled()`.
5
+ * @abstract
6
+ * @class
7
+ */
8
+ export default class AbstractEvent {
9
+ static type = 'event';
10
+ static cancelable = false;
11
+
12
+ constructor(data) {
13
+ this._canceled = false;
14
+ this.data = data;
15
+ }
16
+
17
+ get type() {
18
+ return this.constructor.type;
19
+ }
20
+
21
+ get cancelable() {
22
+ return this.constructor.cancelable;
23
+ }
24
+
25
+ /**
26
+ * Cancels a specific event
27
+ * @abstract
28
+ */
29
+ cancel() {
30
+ // We should be declaring if events are cancelable
31
+ // if (!this.cancelable) {
32
+ // throw new Error('This event is not cancelable');
33
+ // }
34
+ this._canceled = true;
35
+ }
36
+
37
+ /**
38
+ * Check if event has been canceled
39
+ * @abstract
40
+ * @return {Boolean}
41
+ */
42
+ canceled() {
43
+ return Boolean(this._canceled);
44
+ }
45
+ }
@@ -0,0 +1,25 @@
1
+ import AbstractEvent from './abstract-event';
2
+
3
+ export class CollidableEvent extends AbstractEvent {
4
+ static type = 'collidable';
5
+
6
+ get dragEvent() {
7
+ return this.data.dragEvent;
8
+ }
9
+ }
10
+
11
+ export class CollidableInEvent extends CollidableEvent {
12
+ static type = 'collidable:in';
13
+
14
+ get collidingElement() {
15
+ return this.data.collidingElement;
16
+ }
17
+ }
18
+
19
+ export class CollidableOutEvent extends CollidableEvent {
20
+ static type = 'collidable:out';
21
+
22
+ get collidingElement() {
23
+ return this.data.collidingElement;
24
+ }
25
+ }
@@ -0,0 +1,91 @@
1
+ import AbstractEvent from './abstract-event';
2
+
3
+ export class DragEvent extends AbstractEvent {
4
+ get source() {
5
+ return this.data.source;
6
+ }
7
+
8
+ get mirror() {
9
+ return this.data.mirror;
10
+ }
11
+
12
+ get sourceContainer() {
13
+ return this.data.sourceContainer;
14
+ }
15
+
16
+ get sensorEvent() {
17
+ return this.data.sensorEvent;
18
+ }
19
+
20
+ get originalEvent() {
21
+ if (this.sensorEvent) {
22
+ return this.sensorEvent.originalEvent;
23
+ }
24
+
25
+ return null;
26
+ }
27
+
28
+ hasMirror() {
29
+ return Boolean(this.mirror);
30
+ }
31
+ }
32
+
33
+ export class DragStartEvent extends DragEvent {
34
+ static type = 'drag:start';
35
+ }
36
+
37
+ export class DragMoveEvent extends DragEvent {
38
+ static type = 'drag:move';
39
+ }
40
+
41
+ export class DragOutContainerEvent extends DragEvent {
42
+ static type = 'drag:out:container';
43
+
44
+ get overContainer() {
45
+ return this.data.overContainer;
46
+ }
47
+ }
48
+
49
+ export class DragOutEvent extends DragEvent {
50
+ static type = 'drag:out';
51
+
52
+ get overContainer() {
53
+ return this.data.overContainer;
54
+ }
55
+
56
+ get over() {
57
+ return this.data.over;
58
+ }
59
+ }
60
+
61
+ export class DragOverContainerEvent extends DragEvent {
62
+ static type = 'drag:over:container';
63
+
64
+ get overContainer() {
65
+ return this.data.overContainer;
66
+ }
67
+ }
68
+
69
+ export class DragOverEvent extends DragEvent {
70
+ static type = 'drag:over';
71
+
72
+ get overContainer() {
73
+ return this.data.overContainer;
74
+ }
75
+
76
+ get over() {
77
+ return this.data.over;
78
+ }
79
+ }
80
+
81
+ export class DragPressureEvent extends DragEvent {
82
+ static type = 'drag:pressure';
83
+
84
+ get pressure() {
85
+ return this.data.pressure;
86
+ }
87
+ }
88
+
89
+ export class DragStopEvent extends DragEvent {
90
+ static type = 'drag:stop';
91
+ }
@@ -0,0 +1,17 @@
1
+ import AbstractEvent from './abstract-event';
2
+
3
+ export class DraggableEvent extends AbstractEvent {
4
+ static type = 'draggable';
5
+
6
+ get draggable() {
7
+ return this.data.draggable;
8
+ }
9
+ }
10
+
11
+ export class DraggableInitializedEvent extends DraggableEvent {
12
+ static type = 'draggable:initialize';
13
+ }
14
+
15
+ export class DraggableDestroyEvent extends DraggableEvent {
16
+ static type = 'draggable:destroy';
17
+ }
@@ -0,0 +1,21 @@
1
+ import AbstractEvent from './abstract-event';
2
+
3
+ export class DroppableEvent extends AbstractEvent {
4
+ static type = 'droppable';
5
+
6
+ get dragEvent() {
7
+ return this.data.dragEvent;
8
+ }
9
+
10
+ get droppable() {
11
+ return this.data.droppable;
12
+ }
13
+ }
14
+
15
+ export class DroppableOverEvent extends DroppableEvent {
16
+ static type = 'droppable:over';
17
+ }
18
+
19
+ export class DroppableOutEvent extends DroppableEvent {
20
+ static type = 'droppable:out';
21
+ }
@@ -0,0 +1,43 @@
1
+ import AbstractEvent from './abstract-event';
2
+
3
+ export class MirrorEvent extends AbstractEvent {
4
+ get source() {
5
+ return this.data.source;
6
+ }
7
+
8
+ get mirror() {
9
+ return this.data.mirror;
10
+ }
11
+
12
+ get sourceContainer() {
13
+ return this.data.sourceContainer;
14
+ }
15
+
16
+ get sensorEvent() {
17
+ return this.data.sensorEvent;
18
+ }
19
+
20
+ get originalEvent() {
21
+ if (this.sensorEvent) {
22
+ return this.sensorEvent.originalEvent;
23
+ }
24
+
25
+ return null;
26
+ }
27
+ }
28
+
29
+ export class MirrorCreatedEvent extends MirrorEvent {
30
+ static type = 'mirror:created';
31
+ }
32
+
33
+ export class MirrorAttachedEvent extends MirrorEvent {
34
+ static type = 'mirror:attached';
35
+ }
36
+
37
+ export class MirrorMoveEvent extends MirrorEvent {
38
+ static type = 'mirror:move';
39
+ }
40
+
41
+ export class MirrorDestroyEvent extends MirrorEvent {
42
+ static type = 'mirror:destroy';
43
+ }
@@ -0,0 +1,47 @@
1
+ import AbstractEvent from './abstract-event';
2
+
3
+ export class SensorEvent extends AbstractEvent {
4
+ get originalEvent() {
5
+ return this.data.originalEvent;
6
+ }
7
+
8
+ get clientX() {
9
+ return this.data.clientX;
10
+ }
11
+
12
+ get clientY() {
13
+ return this.data.clientY;
14
+ }
15
+
16
+ get target() {
17
+ return this.data.target;
18
+ }
19
+
20
+ get container() {
21
+ return this.data.container;
22
+ }
23
+
24
+ get overContainer() {
25
+ return this.data.overContainer;
26
+ }
27
+
28
+ get pressure() {
29
+ return this.data.pressure;
30
+ }
31
+ }
32
+
33
+ export class DragStartSensorEvent extends SensorEvent {
34
+ static type = 'drag:start';
35
+ }
36
+
37
+ export class DragMoveSensorEvent extends SensorEvent {
38
+ static type = 'drag:move';
39
+ }
40
+
41
+ export class DragStopSensorEvent extends SensorEvent {
42
+ static type = 'drag:stop';
43
+ }
44
+
45
+ export class DragPressureSensorEvent extends SensorEvent {
46
+ static type = 'drag:pressure';
47
+ }