UNPKG

15.9 kBJavaScriptView Raw
1/*syn@0.14.0#drag*/
2var syn = require('./synthetic.js');
3var elementFromPoint = function (point, win) {
4 var clientX = point.clientX;
5 var clientY = point.clientY;
6 if (point == null) {
7 return null;
8 }
9 if (syn.support.elementFromPage) {
10 var off = syn.helpers.scrollOffset(win);
11 clientX = clientX + off.left;
12 clientY = clientY + off.top;
13 }
14 return win.document.elementFromPoint(Math.round(clientX), Math.round(clientY));
15};
16var DragonDrop = {
17 html5drag: false,
18 focusWindow: null,
19 dragAndDrop: function (focusWindow, fromPoint, toPoint, duration, callback) {
20 this.currentDataTransferItem = null;
21 this.focusWindow = focusWindow;
22 this._mouseOver(fromPoint);
23 this._mouseEnter(fromPoint);
24 this._mouseMove(fromPoint);
25 this._mouseDown(fromPoint);
26 this._dragStart(fromPoint);
27 this._drag(fromPoint);
28 this._dragEnter(fromPoint);
29 this._dragOver(fromPoint);
30 DragonDrop.startMove(fromPoint, toPoint, duration, function () {
31 DragonDrop._dragLeave(fromPoint);
32 DragonDrop._dragEnd(fromPoint);
33 DragonDrop._mouseOut(fromPoint);
34 DragonDrop._mouseLeave(fromPoint);
35 DragonDrop._drop(toPoint);
36 DragonDrop._dragEnd(toPoint);
37 DragonDrop._mouseOver(toPoint);
38 DragonDrop._mouseEnter(toPoint);
39 DragonDrop._mouseMove(toPoint);
40 DragonDrop._mouseOut(toPoint);
41 DragonDrop._mouseLeave(toPoint);
42 callback();
43 DragonDrop.cleanup();
44 });
45 },
46 _dragStart: function (node, options) {
47 this.createAndDispatchEvent(node, 'dragstart', options);
48 },
49 _drag: function (node, options) {
50 this.createAndDispatchEvent(node, 'drag', options);
51 },
52 _dragEnter: function (node, options) {
53 this.createAndDispatchEvent(node, 'dragenter', options);
54 },
55 _dragOver: function (node, options) {
56 this.createAndDispatchEvent(node, 'dragover', options);
57 },
58 _dragLeave: function (node, options) {
59 this.createAndDispatchEvent(node, 'dragleave', options);
60 },
61 _drop: function (node, options) {
62 this.createAndDispatchEvent(node, 'drop', options);
63 },
64 _dragEnd: function (node, options) {
65 this.createAndDispatchEvent(node, 'dragend', options);
66 },
67 _mouseDown: function (node, options) {
68 this.createAndDispatchEvent(node, 'mousedown', options);
69 },
70 _mouseMove: function (node, options) {
71 this.createAndDispatchEvent(node, 'mousemove', options);
72 },
73 _mouseEnter: function (node, options) {
74 this.createAndDispatchEvent(node, 'mouseenter', options);
75 },
76 _mouseOver: function (node, options) {
77 this.createAndDispatchEvent(node, 'mouseover', options);
78 },
79 _mouseOut: function (node, options) {
80 this.createAndDispatchEvent(node, 'mouseout', options);
81 },
82 _mouseLeave: function (node, options) {
83 this.createAndDispatchEvent(node, 'mouseleave', options);
84 },
85 createAndDispatchEvent: function (point, eventName, options) {
86 if (point) {
87 var targetElement = elementFromPoint(point, this.focusWindow);
88 syn.trigger(targetElement, eventName, options);
89 }
90 },
91 getDataTransferObject: function () {
92 if (!this.currentDataTransferItem) {
93 return this.currentDataTransferItem = this.createDataTransferObject();
94 } else {
95 return this.currentDataTransferItem;
96 }
97 },
98 cleanup: function () {
99 this.currentDataTransferItem = null;
100 this.focusWindow = null;
101 },
102 createDataTransferObject: function () {
103 var dataTransfer = {
104 dropEffect: 'none',
105 effectAllowed: 'uninitialized',
106 files: [],
107 items: [],
108 types: [],
109 data: [],
110 setData: function (dataFlavor, value) {
111 var tempdata = {};
112 tempdata.dataFlavor = dataFlavor;
113 tempdata.val = value;
114 this.data.push(tempdata);
115 },
116 getData: function (dataFlavor) {
117 for (var i = 0; i < this.data.length; i++) {
118 var tempdata = this.data[i];
119 if (tempdata.dataFlavor === dataFlavor) {
120 return tempdata.val;
121 }
122 }
123 }
124 };
125 return dataTransfer;
126 },
127 startMove: function (start, end, duration, callback) {
128 var startTime = new Date();
129 var distX = end.clientX - start.clientX;
130 var distY = end.clientY - start.clientY;
131 var win = this.focusWindow;
132 var current = start;
133 var cursor = win.document.createElement('div');
134 var calls = 0;
135 var move;
136 move = function onmove() {
137 var now = new Date();
138 var scrollOffset = syn.helpers.scrollOffset(win);
139 var fraction = (calls === 0 ? 0 : now - startTime) / duration;
140 var options = {
141 clientX: distX * fraction + start.clientX,
142 clientY: distY * fraction + start.clientY
143 };
144 calls++;
145 if (fraction < 1) {
146 syn.helpers.extend(cursor.style, {
147 left: options.clientX + scrollOffset.left + 2 + 'px',
148 top: options.clientY + scrollOffset.top + 2 + 'px'
149 });
150 current = DragonDrop.mouseMove(options, current);
151 syn.schedule(onmove, 15);
152 } else {
153 current = DragonDrop.mouseMove(end, current);
154 win.document.body.removeChild(cursor);
155 callback();
156 }
157 };
158 syn.helpers.extend(cursor.style, {
159 height: '5px',
160 width: '5px',
161 backgroundColor: 'red',
162 position: 'absolute',
163 zIndex: 19999,
164 fontSize: '1px'
165 });
166 win.document.body.appendChild(cursor);
167 move();
168 },
169 mouseMove: function (thisPoint, previousPoint) {
170 var thisElement = elementFromPoint(thisPoint, this.focusWindow);
171 var previousElement = elementFromPoint(previousPoint, this.focusWindow);
172 var options = syn.helpers.extend({}, thisPoint);
173 if (thisElement !== previousElement) {
174 options.relatedTarget = thisElement;
175 this._dragLeave(previousPoint, options);
176 options.relatedTarget = previousElement;
177 this._dragEnter(thisPoint, options);
178 }
179 this._dragOver(thisPoint, options);
180 return thisPoint;
181 }
182};
183function createDragEvent(eventName, options, element) {
184 var dragEvent = syn.create.mouse.event(eventName, options, element);
185 dragEvent.dataTransfer = DragonDrop.getDataTransferObject();
186 return syn.dispatch(dragEvent, element, eventName, false);
187}
188syn.create.dragstart = { event: createDragEvent };
189syn.create.dragenter = { event: createDragEvent };
190syn.create.dragover = { event: createDragEvent };
191syn.create.dragleave = { event: createDragEvent };
192syn.create.drag = { event: createDragEvent };
193syn.create.drop = { event: createDragEvent };
194syn.create.dragend = { event: createDragEvent };
195(function dragSupport() {
196 if (!document.body) {
197 syn.schedule(dragSupport, 1);
198 return;
199 }
200 var div = document.createElement('div');
201 document.body.appendChild(div);
202 syn.helpers.extend(div.style, {
203 width: '100px',
204 height: '10000px',
205 backgroundColor: 'blue',
206 position: 'absolute',
207 top: '10px',
208 left: '0px',
209 zIndex: 19999
210 });
211 document.body.scrollTop = 11;
212 if (!document.elementFromPoint) {
213 return;
214 }
215 var el = document.elementFromPoint(3, 1);
216 if (el === div) {
217 syn.support.elementFromClient = true;
218 } else {
219 syn.support.elementFromPage = true;
220 }
221 document.body.removeChild(div);
222 document.body.scrollTop = 0;
223}());
224var mouseMove = function (point, win, last) {
225 var el = elementFromPoint(point, win);
226 if (last !== el && el && last) {
227 var options = syn.helpers.extend({}, point);
228 options.relatedTarget = el;
229 if (syn.support.pointerEvents) {
230 syn.trigger(last, 'pointerout', options);
231 syn.trigger(last, 'pointerleave', options);
232 }
233 syn.trigger(last, 'mouseout', options);
234 syn.trigger(last, 'mouseleave', options);
235 options.relatedTarget = last;
236 if (syn.support.pointerEvents) {
237 syn.trigger(el, 'pointerover', options);
238 syn.trigger(el, 'pointerenter', options);
239 }
240 syn.trigger(el, 'mouseover', options);
241 syn.trigger(el, 'mouseenter', options);
242 }
243 if (syn.support.pointerEvents) {
244 syn.trigger(el || win, 'pointermove', point);
245 }
246 if (syn.support.touchEvents) {
247 syn.trigger(el || win, 'touchmove', point);
248 }
249 if (DragonDrop.html5drag) {
250 if (!syn.support.pointerEvents) {
251 syn.trigger(el || win, 'mousemove', point);
252 }
253 } else {
254 syn.trigger(el || win, 'mousemove', point);
255 }
256 return el;
257 }, createEventAtPoint = function (event, point, win) {
258 var el = elementFromPoint(point, win);
259 syn.trigger(el || win, event, point);
260 return el;
261 }, startMove = function (win, start, end, duration, callback) {
262 var startTime = new Date(), distX = end.clientX - start.clientX, distY = end.clientY - start.clientY, current = elementFromPoint(start, win), cursor = win.document.createElement('div'), calls = 0, move;
263 move = function onmove() {
264 var now = new Date(), scrollOffset = syn.helpers.scrollOffset(win), fraction = (calls === 0 ? 0 : now - startTime) / duration, options = {
265 clientX: distX * fraction + start.clientX,
266 clientY: distY * fraction + start.clientY
267 };
268 calls++;
269 if (fraction < 1) {
270 syn.helpers.extend(cursor.style, {
271 left: options.clientX + scrollOffset.left + 2 + 'px',
272 top: options.clientY + scrollOffset.top + 2 + 'px'
273 });
274 current = mouseMove(options, win, current);
275 syn.schedule(onmove, 15);
276 } else {
277 current = mouseMove(end, win, current);
278 win.document.body.removeChild(cursor);
279 callback();
280 }
281 };
282 syn.helpers.extend(cursor.style, {
283 height: '5px',
284 width: '5px',
285 backgroundColor: 'red',
286 position: 'absolute',
287 zIndex: 19999,
288 fontSize: '1px'
289 });
290 win.document.body.appendChild(cursor);
291 move();
292 }, startDrag = function (win, fromPoint, toPoint, duration, callback) {
293 if (syn.support.pointerEvents) {
294 createEventAtPoint('pointerover', fromPoint, win);
295 createEventAtPoint('pointerenter', fromPoint, win);
296 }
297 createEventAtPoint('mouseover', fromPoint, win);
298 createEventAtPoint('mouseenter', fromPoint, win);
299 if (syn.support.pointerEvents) {
300 createEventAtPoint('pointermove', fromPoint, win);
301 }
302 createEventAtPoint('mousemove', fromPoint, win);
303 if (syn.support.pointerEvents) {
304 createEventAtPoint('pointerdown', fromPoint, win);
305 }
306 if (syn.support.touchEvents) {
307 createEventAtPoint('touchstart', fromPoint, win);
308 }
309 createEventAtPoint('mousedown', fromPoint, win);
310 startMove(win, fromPoint, toPoint, duration, function () {
311 if (syn.support.pointerEvents) {
312 createEventAtPoint('pointerup', toPoint, win);
313 }
314 if (syn.support.touchEvents) {
315 createEventAtPoint('touchend', toPoint, win);
316 }
317 createEventAtPoint('mouseup', toPoint, win);
318 if (syn.support.pointerEvents) {
319 createEventAtPoint('pointerleave', toPoint, win);
320 }
321 createEventAtPoint('mouseleave', toPoint, win);
322 callback();
323 });
324 }, center = function (el) {
325 var j = syn.jquery()(el), o = j.offset();
326 return {
327 pageX: o.left + j.outerWidth() / 2,
328 pageY: o.top + j.outerHeight() / 2
329 };
330 }, convertOption = function (option, win, from) {
331 var page = /(\d+)[x ](\d+)/, client = /(\d+)X(\d+)/, relative = /([+-]\d+)[xX ]([+-]\d+)/, parts;
332 if (typeof option === 'string' && relative.test(option) && from) {
333 var cent = center(from);
334 parts = option.match(relative);
335 option = {
336 pageX: cent.pageX + parseInt(parts[1]),
337 pageY: cent.pageY + parseInt(parts[2])
338 };
339 }
340 if (typeof option === 'string' && page.test(option)) {
341 parts = option.match(page);
342 option = {
343 pageX: parseInt(parts[1]),
344 pageY: parseInt(parts[2])
345 };
346 }
347 if (typeof option === 'string' && client.test(option)) {
348 parts = option.match(client);
349 option = {
350 clientX: parseInt(parts[1]),
351 clientY: parseInt(parts[2])
352 };
353 }
354 if (typeof option === 'string') {
355 option = syn.jquery()(option, win.document)[0];
356 }
357 if (option.nodeName) {
358 option = center(option);
359 }
360 if (option.pageX != null) {
361 var off = syn.helpers.scrollOffset(win);
362 option = {
363 clientX: option.pageX - off.left,
364 clientY: option.pageY - off.top
365 };
366 }
367 return option;
368 }, adjust = function (from, to, win) {
369 if (from.clientY < 0) {
370 var off = syn.helpers.scrollOffset(win);
371 var top = off.top + from.clientY - 100, diff = top - off.top;
372 if (top > 0) {
373 } else {
374 top = 0;
375 diff = -off.top;
376 }
377 from.clientY = from.clientY - diff;
378 to.clientY = to.clientY - diff;
379 syn.helpers.scrollOffset(win, {
380 top: top,
381 left: off.left
382 });
383 }
384 };
385syn.helpers.extend(syn.init.prototype, {
386 _move: function (from, options, callback) {
387 var win = syn.helpers.getWindow(from);
388 var sourceCoordinates = convertOption(options.from || from, win, from);
389 var destinationCoordinates = convertOption(options.to || options, win, from);
390 DragonDrop.html5drag = syn.support.pointerEvents;
391 if (options.adjust !== false) {
392 adjust(sourceCoordinates, destinationCoordinates, win);
393 }
394 startMove(win, sourceCoordinates, destinationCoordinates, options.duration || 500, callback);
395 },
396 _drag: function (from, options, callback) {
397 var win = syn.helpers.getWindow(from);
398 var sourceCoordinates = convertOption(options.from || from, win, from);
399 var destinationCoordinates = convertOption(options.to || options, win, from);
400 if (options.adjust !== false) {
401 adjust(sourceCoordinates, destinationCoordinates, win);
402 }
403 DragonDrop.html5drag = from.draggable;
404 if (DragonDrop.html5drag) {
405 DragonDrop.dragAndDrop(win, sourceCoordinates, destinationCoordinates, options.duration || 500, callback);
406 } else {
407 startDrag(win, sourceCoordinates, destinationCoordinates, options.duration || 500, callback);
408 }
409 }
410});
\No newline at end of file