1 |
|
2 | var syn = require('./synthetic.js');
|
3 | var 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 | };
|
16 | var 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 | };
|
183 | function 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 | }
|
188 | syn.create.dragstart = { event: createDragEvent };
|
189 | syn.create.dragenter = { event: createDragEvent };
|
190 | syn.create.dragover = { event: createDragEvent };
|
191 | syn.create.dragleave = { event: createDragEvent };
|
192 | syn.create.drag = { event: createDragEvent };
|
193 | syn.create.drop = { event: createDragEvent };
|
194 | syn.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 | }());
|
224 | var 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 | };
|
385 | syn.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 |