This repository has been archived by the owner on Nov 9, 2017. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 17
/
angular-draganddrop.js
196 lines (159 loc) · 5.81 KB
/
angular-draganddrop.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/*! Angular draganddrop v0.2.2 | (c) 2013 Greg Bergé | License MIT */
angular
.module('draganddrop', [])
.directive('draggable', draggableDirective)
.directive('drop', ['$parse', dropDirective]);
/**
* Draggable directive.
*
* @example
* <div draggable="true" effect-allowed="link" draggable-type="image" draggable-data="{foo: 'bar'}"></div>
*
* - "draggable" Make the element draggable. Accepts a boolean.
* - "effect-allowed" Allowed effects for the dragged element,
see https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer#effectAllowed.28.29.
Accepts a string.
* - "draggable-type" Type of data object attached to the dragged element, this type
is prefixed by "json/". Accepts a string.
* - "draggable-data" Data attached to the dragged element, data are serialized in JSON.
Accepts an Angular expression.
*/
function draggableDirective() {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var domElement = element[0];
var effectAllowed = attrs.effectAllowed;
var draggableData = attrs.draggableData;
var draggableType = attrs.draggableType;
var draggable = attrs.draggable === 'false' ? false : true;
// Make element draggable or not.
domElement.draggable = draggable;
if (! draggable) return ;
domElement.addEventListener('dragstart', function (e) {
// Restrict drag effect.
e.dataTransfer.effectAllowed = effectAllowed || e.dataTransfer.effectAllowed;
// Eval and serialize data.
var data = scope.$eval(draggableData);
var jsonData = angular.toJson(data);
// Set drag data and drag type.
e.dataTransfer.setData('json/' + draggableType, jsonData);
e.stopPropagation();
});
}
};
}
/**
* Drop directive.
*
* @example
* <div drop="onDrop($data, $event)" drop-effect="link" drop-accept="'json/image'"
* drag-over="onDragOver($event)" drag-over-class="drag-over"></div>
*
* - "drop" Drop handler, executed on drop. Accepts an Angular expression.
* - "drop-effect" Drop effect to set,
see https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer#dropEffect.28.29.
Accepts a string.
* - "drop-accept" Types accepted or function to prevent unauthorized drag and drop.
* Accepts a string, an array, a function or a boolean.
* - "drag-over" Drag over handler, executed on drag over. Accepts an Angular expression.
* - "drag-over-class" Class set on drag over, when the drag is authorized. Accepts a string.
*/
function dropDirective($parse) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var domElement = element[0];
var dropEffect = attrs.dropEffect;
var dropAccept = attrs.dropAccept;
var dragOverClass = attrs.dragOverClass;
var dragOverHandler = $parse(attrs.dragOver);
var dropHandler = $parse(attrs.drop);
domElement.addEventListener('dragover', dragOverListener);
domElement.addEventListener('drop', dropListener);
domElement.addEventListener('dragleave', removeDragOverClass);
scope.$on('$destroy', function () {
domElement.removeEventListener('dragover', dragOverListener);
domElement.removeEventListener('drop', dropListener);
domElement.removeEventListener('dragleave', removeDragOverClass);
});
function dragOverListener(event) {
// Check if type is accepted.
if (! accepts(scope.$eval(dropAccept), event)) return true;
if (dragOverClass) element.addClass(dragOverClass);
// Set up drop effect to link.
event.dataTransfer.dropEffect = dropEffect || event.dataTransfer.dropEffect;
// Call dragOverHandler
scope.$apply(function () {
dragOverHandler(scope, { $event: event });
});
// Prevent default to accept drag and drop.
event.preventDefault();
}
function dropListener(event) {
var data = getData(event);
removeDragOverClass();
// Call dropHandler
scope.$apply(function () {
dropHandler(scope, { $data: data, $event: event });
});
// Prevent default navigator behaviour.
event.preventDefault();
}
/**
* Remove the drag over class.
*/
function removeDragOverClass() {
element.removeClass(dragOverClass);
}
/**
* Test if a type is accepted.
*
* @param {String|Array|Function} type
* @param {Event} event
* @returns {Boolean}
*/
function accepts(type, event) {
if (typeof type === 'boolean') return type;
if (typeof type === 'string') return accepts([type], event);
if (Array.isArray(type)) {
return accepts(function (types) {
return types.some(function (_type) {
return type.indexOf(_type) !== -1;
});
}, event);
}
if (typeof type === 'function') return type(toArray(event.dataTransfer.types));
return false;
}
/**
* Get data from a drag event.
*
* @param {Event} event
* @returns {Object}
*/
function getData(event) {
var types = toArray(event.dataTransfer.types);
return types.reduce(function (collection, type) {
// Get data.
var data = event.dataTransfer.getData(type);
// Get data format.
var format = /(.*)\//.exec(type);
format = format ? format[1] : null;
// Parse data.
if (format === 'json') data = JSON.parse(data);
collection[type] = data;
return collection;
}, {});
}
/**
* Convert a collection to an array.
*
* @param {Object} collection
*/
function toArray(collection) {
return Array.prototype.slice.call(collection);
}
}
};
}