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.
- checksums.yaml +4 -4
- data/lib/draggable/rails/version.rb +1 -1
- data/vendor/assets/javascripts/behaviour/collidable.js +99 -0
- data/vendor/assets/javascripts/behaviour/snappable.js +107 -0
- data/vendor/assets/javascripts/core/accessibility.js +58 -0
- data/vendor/assets/javascripts/core/mirror.js +129 -0
- data/vendor/assets/javascripts/draggable.js +487 -0
- data/vendor/assets/javascripts/droppable.js +168 -0
- data/vendor/assets/javascripts/events/abstract-event.js +45 -0
- data/vendor/assets/javascripts/events/collidable-event.js +25 -0
- data/vendor/assets/javascripts/events/drag-event.js +91 -0
- data/vendor/assets/javascripts/events/draggable-event.js +17 -0
- data/vendor/assets/javascripts/events/droppable-event.js +21 -0
- data/vendor/assets/javascripts/events/mirror-event.js +43 -0
- data/vendor/assets/javascripts/events/sensor-event.js +47 -0
- data/vendor/assets/javascripts/events/snappable-event.js +15 -0
- data/vendor/assets/javascripts/events/sortable-event.js +35 -0
- data/vendor/assets/javascripts/events/swappable-event.js +23 -0
- data/vendor/assets/javascripts/index.js +18 -0
- data/vendor/assets/javascripts/sensors/drag-sensor.js +158 -0
- data/vendor/assets/javascripts/sensors/force-touch-sensor.js +166 -0
- data/vendor/assets/javascripts/sensors/mouse-sensor.js +110 -0
- data/vendor/assets/javascripts/sensors/sensor.js +23 -0
- data/vendor/assets/javascripts/sensors/touch-sensor.js +145 -0
- data/vendor/assets/javascripts/sortable.js +161 -0
- data/vendor/assets/javascripts/swappable.js +104 -0
- data/vendor/assets/javascripts/utils.js +52 -0
- 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
|
+
}
|