Subversion-Projekte lars-tiefland.ci

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
875 lars 1
/**
2
 * ### Drag'n'drop plugin
3
 *
4
 * Enables dragging and dropping of nodes in the tree, resulting in a move or copy operations.
5
 */
6
/*globals jQuery, define, exports, require, document */
7
(function (factory) {
8
	"use strict";
9
	if (typeof define === 'function' && define.amd) {
10
		define('jstree.dnd', ['jquery','jstree'], factory);
11
	}
12
	else if(typeof exports === 'object') {
13
		factory(require('jquery'), require('jstree'));
14
	}
15
	else {
16
		factory(jQuery, jQuery.jstree);
17
	}
18
}(function ($, jstree, undefined) {
19
	"use strict";
20
 
21
	if($.jstree.plugins.dnd) { return; }
22
 
23
	/**
24
	 * stores all defaults for the drag'n'drop plugin
25
	 * @name $.jstree.defaults.dnd
26
	 * @plugin dnd
27
	 */
28
	$.jstree.defaults.dnd = {
29
		/**
30
		 * a boolean indicating if a copy should be possible while dragging (by pressint the meta key or Ctrl). Defaults to `true`.
31
		 * @name $.jstree.defaults.dnd.copy
32
		 * @plugin dnd
33
		 */
34
		copy : true,
35
		/**
36
		 * a number indicating how long a node should remain hovered while dragging to be opened. Defaults to `500`.
37
		 * @name $.jstree.defaults.dnd.open_timeout
38
		 * @plugin dnd
39
		 */
40
		open_timeout : 500,
41
		/**
42
		 * a function invoked each time a node is about to be dragged, invoked in the tree's scope and receives the nodes about to be dragged as an argument (array) and the event that started the drag - return `false` to prevent dragging
43
		 * @name $.jstree.defaults.dnd.is_draggable
44
		 * @plugin dnd
45
		 */
46
		is_draggable : true,
47
		/**
48
		 * a boolean indicating if checks should constantly be made while the user is dragging the node (as opposed to checking only on drop), default is `true`
49
		 * @name $.jstree.defaults.dnd.check_while_dragging
50
		 * @plugin dnd
51
		 */
52
		check_while_dragging : true,
53
		/**
54
		 * a boolean indicating if nodes from this tree should only be copied with dnd (as opposed to moved), default is `false`
55
		 * @name $.jstree.defaults.dnd.always_copy
56
		 * @plugin dnd
57
		 */
58
		always_copy : false,
59
		/**
60
		 * when dropping a node "inside", this setting indicates the position the node should go to - it can be an integer or a string: "first" (same as 0) or "last", default is `0`
61
		 * @name $.jstree.defaults.dnd.inside_pos
62
		 * @plugin dnd
63
		 */
64
		inside_pos : 0,
65
		/**
66
		 * when starting the drag on a node that is selected this setting controls if all selected nodes are dragged or only the single node, default is `true`, which means all selected nodes are dragged when the drag is started on a selected node
67
		 * @name $.jstree.defaults.dnd.drag_selection
68
		 * @plugin dnd
69
		 */
70
		drag_selection : true,
71
		/**
72
		 * controls whether dnd works on touch devices. If left as boolean true dnd will work the same as in desktop browsers, which in some cases may impair scrolling. If set to boolean false dnd will not work on touch devices. There is a special third option - string "selected" which means only selected nodes can be dragged on touch devices.
73
		 * @name $.jstree.defaults.dnd.touch
74
		 * @plugin dnd
75
		 */
76
		touch : true,
77
		/**
78
		 * controls whether items can be dropped anywhere on the node, not just on the anchor, by default only the node anchor is a valid drop target. Works best with the wholerow plugin. If enabled on mobile depending on the interface it might be hard for the user to cancel the drop, since the whole tree container will be a valid drop target.
79
		 * @name $.jstree.defaults.dnd.large_drop_target
80
		 * @plugin dnd
81
		 */
82
		large_drop_target : false,
83
		/**
84
		 * controls whether a drag can be initiated from any part of the node and not just the text/icon part, works best with the wholerow plugin. Keep in mind it can cause problems with tree scrolling on mobile depending on the interface - in that case set the touch option to "selected".
85
		 * @name $.jstree.defaults.dnd.large_drag_target
86
		 * @plugin dnd
87
		 */
88
		large_drag_target : false
89
	};
90
	// TODO: now check works by checking for each node individually, how about max_children, unique, etc?
91
	$.jstree.plugins.dnd = function (options, parent) {
92
		this.bind = function () {
93
			parent.bind.call(this);
94
 
95
			this.element
96
				.on('mousedown.jstree touchstart.jstree', this.settings.dnd.large_drag_target ? '.jstree-node' : '.jstree-anchor', $.proxy(function (e) {
97
					if(this.settings.dnd.large_drag_target && $(e.target).closest('.jstree-node')[0] !== e.currentTarget) {
98
						return true;
99
					}
100
					if(e.type === "touchstart" && (!this.settings.dnd.touch || (this.settings.dnd.touch === 'selected' && !$(e.currentTarget).closest('.jstree-node').children('.jstree-anchor').hasClass('jstree-clicked')))) {
101
						return true;
102
					}
103
					var obj = this.get_node(e.target),
104
						mlt = this.is_selected(obj) && this.settings.dnd.drag_selection ? this.get_top_selected().length : 1,
105
						txt = (mlt > 1 ? mlt + ' ' + this.get_string('nodes') : this.get_text(e.currentTarget));
106
					if(this.settings.core.force_text) {
107
						txt = $.vakata.html.escape(txt);
108
					}
109
					if(obj && obj.id && obj.id !== $.jstree.root && (e.which === 1 || e.type === "touchstart") &&
110
						(this.settings.dnd.is_draggable === true || ($.isFunction(this.settings.dnd.is_draggable) && this.settings.dnd.is_draggable.call(this, (mlt > 1 ? this.get_top_selected(true) : [obj]), e)))
111
					) {
112
						this.element.trigger('mousedown.jstree');
113
						return $.vakata.dnd.start(e, { 'jstree' : true, 'origin' : this, 'obj' : this.get_node(obj,true), 'nodes' : mlt > 1 ? this.get_top_selected() : [obj.id] }, '<div id="jstree-dnd" class="jstree-' + this.get_theme() + ' jstree-' + this.get_theme() + '-' + this.get_theme_variant() + ' ' + ( this.settings.core.themes.responsive ? ' jstree-dnd-responsive' : '' ) + '"><i class="jstree-icon jstree-er"></i>' + txt + '<ins class="jstree-copy" style="display:none;">+</ins></div>');
114
					}
115
				}, this));
116
		};
117
	};
118
 
119
	$(function() {
120
		// bind only once for all instances
121
		var lastmv = false,
122
			laster = false,
123
			lastev = false,
124
			opento = false,
125
			marker = $('<div id="jstree-marker">&#160;</div>').hide(); //.appendTo('body');
126
 
127
		$(document)
128
			.on('dnd_start.vakata.jstree', function (e, data) {
129
				lastmv = false;
130
				lastev = false;
131
				if(!data || !data.data || !data.data.jstree) { return; }
132
				marker.appendTo('body'); //.show();
133
			})
134
			.on('dnd_move.vakata.jstree', function (e, data) {
135
				if(opento) { clearTimeout(opento); }
136
				if(!data || !data.data || !data.data.jstree) { return; }
137
 
138
				// if we are hovering the marker image do nothing (can happen on "inside" drags)
139
				if(data.event.target.id && data.event.target.id === 'jstree-marker') {
140
					return;
141
				}
142
				lastev = data.event;
143
 
144
				var ins = $.jstree.reference(data.event.target),
145
					ref = false,
146
					off = false,
147
					rel = false,
148
					tmp, l, t, h, p, i, o, ok, t1, t2, op, ps, pr, ip, tm;
149
				// if we are over an instance
150
				if(ins && ins._data && ins._data.dnd) {
151
					marker.attr('class', 'jstree-' + ins.get_theme() + ( ins.settings.core.themes.responsive ? ' jstree-dnd-responsive' : '' ));
152
					data.helper
153
						.children().attr('class', 'jstree-' + ins.get_theme() + ' jstree-' + ins.get_theme() + '-' + ins.get_theme_variant() + ' ' + ( ins.settings.core.themes.responsive ? ' jstree-dnd-responsive' : '' ))
154
						.find('.jstree-copy').first()[ data.data.origin && (data.data.origin.settings.dnd.always_copy || (data.data.origin.settings.dnd.copy && (data.event.metaKey || data.event.ctrlKey))) ? 'show' : 'hide' ]();
155
 
156
 
157
					// if are hovering the container itself add a new root node
158
					if( (data.event.target === ins.element[0] || data.event.target === ins.get_container_ul()[0]) && ins.get_container_ul().children().length === 0) {
159
						ok = true;
160
						for(t1 = 0, t2 = data.data.nodes.length; t1 < t2; t1++) {
161
							ok = ok && ins.check( (data.data.origin && (data.data.origin.settings.dnd.always_copy || (data.data.origin.settings.dnd.copy && (data.event.metaKey || data.event.ctrlKey)) ) ? "copy_node" : "move_node"), (data.data.origin && data.data.origin !== ins ? data.data.origin.get_node(data.data.nodes[t1]) : data.data.nodes[t1]), $.jstree.root, 'last', { 'dnd' : true, 'ref' : ins.get_node($.jstree.root), 'pos' : 'i', 'origin' : data.data.origin, 'is_multi' : (data.data.origin && data.data.origin !== ins), 'is_foreign' : (!data.data.origin) });
162
							if(!ok) { break; }
163
						}
164
						if(ok) {
165
							lastmv = { 'ins' : ins, 'par' : $.jstree.root, 'pos' : 'last' };
166
							marker.hide();
167
							data.helper.find('.jstree-icon').first().removeClass('jstree-er').addClass('jstree-ok');
168
							return;
169
						}
170
					}
171
					else {
172
						// if we are hovering a tree node
173
						ref = ins.settings.dnd.large_drop_target ? $(data.event.target).closest('.jstree-node').children('.jstree-anchor') : $(data.event.target).closest('.jstree-anchor');
174
						if(ref && ref.length && ref.parent().is('.jstree-closed, .jstree-open, .jstree-leaf')) {
175
							off = ref.offset();
176
							rel = data.event.pageY - off.top;
177
							h = ref.outerHeight();
178
							if(rel < h / 3) {
179
								o = ['b', 'i', 'a'];
180
							}
181
							else if(rel > h - h / 3) {
182
								o = ['a', 'i', 'b'];
183
							}
184
							else {
185
								o = rel > h / 2 ? ['i', 'a', 'b'] : ['i', 'b', 'a'];
186
							}
187
							$.each(o, function (j, v) {
188
								switch(v) {
189
									case 'b':
190
										l = off.left - 6;
191
										t = off.top;
192
										p = ins.get_parent(ref);
193
										i = ref.parent().index();
194
										break;
195
									case 'i':
196
										ip = ins.settings.dnd.inside_pos;
197
										tm = ins.get_node(ref.parent());
198
										l = off.left - 2;
199
										t = off.top + h / 2 + 1;
200
										p = tm.id;
201
										i = ip === 'first' ? 0 : (ip === 'last' ? tm.children.length : Math.min(ip, tm.children.length));
202
										break;
203
									case 'a':
204
										l = off.left - 6;
205
										t = off.top + h;
206
										p = ins.get_parent(ref);
207
										i = ref.parent().index() + 1;
208
										break;
209
								}
210
								ok = true;
211
								for(t1 = 0, t2 = data.data.nodes.length; t1 < t2; t1++) {
212
									op = data.data.origin && (data.data.origin.settings.dnd.always_copy || (data.data.origin.settings.dnd.copy && (data.event.metaKey || data.event.ctrlKey))) ? "copy_node" : "move_node";
213
									ps = i;
214
									if(op === "move_node" && v === 'a' && (data.data.origin && data.data.origin === ins) && p === ins.get_parent(data.data.nodes[t1])) {
215
										pr = ins.get_node(p);
216
										if(ps > $.inArray(data.data.nodes[t1], pr.children)) {
217
											ps -= 1;
218
										}
219
									}
220
									ok = ok && ( (ins && ins.settings && ins.settings.dnd && ins.settings.dnd.check_while_dragging === false) || ins.check(op, (data.data.origin && data.data.origin !== ins ? data.data.origin.get_node(data.data.nodes[t1]) : data.data.nodes[t1]), p, ps, { 'dnd' : true, 'ref' : ins.get_node(ref.parent()), 'pos' : v, 'origin' : data.data.origin, 'is_multi' : (data.data.origin && data.data.origin !== ins), 'is_foreign' : (!data.data.origin) }) );
221
									if(!ok) {
222
										if(ins && ins.last_error) { laster = ins.last_error(); }
223
										break;
224
									}
225
								}
226
								if(v === 'i' && ref.parent().is('.jstree-closed') && ins.settings.dnd.open_timeout) {
227
									opento = setTimeout((function (x, z) { return function () { x.open_node(z); }; }(ins, ref)), ins.settings.dnd.open_timeout);
228
								}
229
								if(ok) {
230
									lastmv = { 'ins' : ins, 'par' : p, 'pos' : v === 'i' && ip === 'last' && i === 0 && !ins.is_loaded(tm) ? 'last' : i };
231
									marker.css({ 'left' : l + 'px', 'top' : t + 'px' }).show();
232
									data.helper.find('.jstree-icon').first().removeClass('jstree-er').addClass('jstree-ok');
233
									laster = {};
234
									o = true;
235
									return false;
236
								}
237
							});
238
							if(o === true) { return; }
239
						}
240
					}
241
				}
242
				lastmv = false;
243
				data.helper.find('.jstree-icon').removeClass('jstree-ok').addClass('jstree-er');
244
				marker.hide();
245
			})
246
			.on('dnd_scroll.vakata.jstree', function (e, data) {
247
				if(!data || !data.data || !data.data.jstree) { return; }
248
				marker.hide();
249
				lastmv = false;
250
				lastev = false;
251
				data.helper.find('.jstree-icon').first().removeClass('jstree-ok').addClass('jstree-er');
252
			})
253
			.on('dnd_stop.vakata.jstree', function (e, data) {
254
				if(opento) { clearTimeout(opento); }
255
				if(!data || !data.data || !data.data.jstree) { return; }
256
				marker.hide().detach();
257
				var i, j, nodes = [];
258
				if(lastmv) {
259
					for(i = 0, j = data.data.nodes.length; i < j; i++) {
260
						nodes[i] = data.data.origin ? data.data.origin.get_node(data.data.nodes[i]) : data.data.nodes[i];
261
					}
262
					lastmv.ins[ data.data.origin && (data.data.origin.settings.dnd.always_copy || (data.data.origin.settings.dnd.copy && (data.event.metaKey || data.event.ctrlKey))) ? 'copy_node' : 'move_node' ](nodes, lastmv.par, lastmv.pos, false, false, false, data.data.origin);
263
				}
264
				else {
265
					i = $(data.event.target).closest('.jstree');
266
					if(i.length && laster && laster.error && laster.error === 'check') {
267
						i = i.jstree(true);
268
						if(i) {
269
							i.settings.core.error.call(this, laster);
270
						}
271
					}
272
				}
273
				lastev = false;
274
				lastmv = false;
275
			})
276
			.on('keyup.jstree keydown.jstree', function (e, data) {
277
				data = $.vakata.dnd._get();
278
				if(data && data.data && data.data.jstree) {
279
					data.helper.find('.jstree-copy').first()[ data.data.origin && (data.data.origin.settings.dnd.always_copy || (data.data.origin.settings.dnd.copy && (e.metaKey || e.ctrlKey))) ? 'show' : 'hide' ]();
280
					if(lastev) {
281
						lastev.metaKey = e.metaKey;
282
						lastev.ctrlKey = e.ctrlKey;
283
						$.vakata.dnd._trigger('move', lastev);
284
					}
285
				}
286
			});
287
	});
288
 
289
	// helpers
290
	(function ($) {
291
		$.vakata.html = {
292
			div : $('<div />'),
293
			escape : function (str) {
294
				return $.vakata.html.div.text(str).html();
295
			},
296
			strip : function (str) {
297
				return $.vakata.html.div.empty().append($.parseHTML(str)).text();
298
			}
299
		};
300
		// private variable
301
		var vakata_dnd = {
302
			element	: false,
303
			target	: false,
304
			is_down	: false,
305
			is_drag	: false,
306
			helper	: false,
307
			helper_w: 0,
308
			data	: false,
309
			init_x	: 0,
310
			init_y	: 0,
311
			scroll_l: 0,
312
			scroll_t: 0,
313
			scroll_e: false,
314
			scroll_i: false,
315
			is_touch: false
316
		};
317
		$.vakata.dnd = {
318
			settings : {
319
				scroll_speed		: 10,
320
				scroll_proximity	: 20,
321
				helper_left			: 5,
322
				helper_top			: 10,
323
				threshold			: 5,
324
				threshold_touch		: 50
325
			},
326
			_trigger : function (event_name, e) {
327
				var data = $.vakata.dnd._get();
328
				data.event = e;
329
				$(document).triggerHandler("dnd_" + event_name + ".vakata", data);
330
			},
331
			_get : function () {
332
				return {
333
					"data"		: vakata_dnd.data,
334
					"element"	: vakata_dnd.element,
335
					"helper"	: vakata_dnd.helper
336
				};
337
			},
338
			_clean : function () {
339
				if(vakata_dnd.helper) { vakata_dnd.helper.remove(); }
340
				if(vakata_dnd.scroll_i) { clearInterval(vakata_dnd.scroll_i); vakata_dnd.scroll_i = false; }
341
				vakata_dnd = {
342
					element	: false,
343
					target	: false,
344
					is_down	: false,
345
					is_drag	: false,
346
					helper	: false,
347
					helper_w: 0,
348
					data	: false,
349
					init_x	: 0,
350
					init_y	: 0,
351
					scroll_l: 0,
352
					scroll_t: 0,
353
					scroll_e: false,
354
					scroll_i: false,
355
					is_touch: false
356
				};
357
				$(document).off("mousemove.vakata.jstree touchmove.vakata.jstree", $.vakata.dnd.drag);
358
				$(document).off("mouseup.vakata.jstree touchend.vakata.jstree", $.vakata.dnd.stop);
359
			},
360
			_scroll : function (init_only) {
361
				if(!vakata_dnd.scroll_e || (!vakata_dnd.scroll_l && !vakata_dnd.scroll_t)) {
362
					if(vakata_dnd.scroll_i) { clearInterval(vakata_dnd.scroll_i); vakata_dnd.scroll_i = false; }
363
					return false;
364
				}
365
				if(!vakata_dnd.scroll_i) {
366
					vakata_dnd.scroll_i = setInterval($.vakata.dnd._scroll, 100);
367
					return false;
368
				}
369
				if(init_only === true) { return false; }
370
 
371
				var i = vakata_dnd.scroll_e.scrollTop(),
372
					j = vakata_dnd.scroll_e.scrollLeft();
373
				vakata_dnd.scroll_e.scrollTop(i + vakata_dnd.scroll_t * $.vakata.dnd.settings.scroll_speed);
374
				vakata_dnd.scroll_e.scrollLeft(j + vakata_dnd.scroll_l * $.vakata.dnd.settings.scroll_speed);
375
				if(i !== vakata_dnd.scroll_e.scrollTop() || j !== vakata_dnd.scroll_e.scrollLeft()) {
376
					/**
377
					 * triggered on the document when a drag causes an element to scroll
378
					 * @event
379
					 * @plugin dnd
380
					 * @name dnd_scroll.vakata
381
					 * @param {Mixed} data any data supplied with the call to $.vakata.dnd.start
382
					 * @param {DOM} element the DOM element being dragged
383
					 * @param {jQuery} helper the helper shown next to the mouse
384
					 * @param {jQuery} event the element that is scrolling
385
					 */
386
					$.vakata.dnd._trigger("scroll", vakata_dnd.scroll_e);
387
				}
388
			},
389
			start : function (e, data, html) {
390
				if(e.type === "touchstart" && e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0]) {
391
					e.pageX = e.originalEvent.changedTouches[0].pageX;
392
					e.pageY = e.originalEvent.changedTouches[0].pageY;
393
					e.target = document.elementFromPoint(e.originalEvent.changedTouches[0].pageX - window.pageXOffset, e.originalEvent.changedTouches[0].pageY - window.pageYOffset);
394
				}
395
				if(vakata_dnd.is_drag) { $.vakata.dnd.stop({}); }
396
				try {
397
					e.currentTarget.unselectable = "on";
398
					e.currentTarget.onselectstart = function() { return false; };
399
					if(e.currentTarget.style) { e.currentTarget.style.MozUserSelect = "none"; }
400
				} catch(ignore) { }
401
				vakata_dnd.init_x	= e.pageX;
402
				vakata_dnd.init_y	= e.pageY;
403
				vakata_dnd.data		= data;
404
				vakata_dnd.is_down	= true;
405
				vakata_dnd.element	= e.currentTarget;
406
				vakata_dnd.target	= e.target;
407
				vakata_dnd.is_touch	= e.type === "touchstart";
408
				if(html !== false) {
409
					vakata_dnd.helper = $("<div id='vakata-dnd'></div>").html(html).css({
410
						"display"		: "block",
411
						"margin"		: "0",
412
						"padding"		: "0",
413
						"position"		: "absolute",
414
						"top"			: "-2000px",
415
						"lineHeight"	: "16px",
416
						"zIndex"		: "10000"
417
					});
418
				}
419
				$(document).on("mousemove.vakata.jstree touchmove.vakata.jstree", $.vakata.dnd.drag);
420
				$(document).on("mouseup.vakata.jstree touchend.vakata.jstree", $.vakata.dnd.stop);
421
				return false;
422
			},
423
			drag : function (e) {
424
				if(e.type === "touchmove" && e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0]) {
425
					e.pageX = e.originalEvent.changedTouches[0].pageX;
426
					e.pageY = e.originalEvent.changedTouches[0].pageY;
427
					e.target = document.elementFromPoint(e.originalEvent.changedTouches[0].pageX - window.pageXOffset, e.originalEvent.changedTouches[0].pageY - window.pageYOffset);
428
				}
429
				if(!vakata_dnd.is_down) { return; }
430
				if(!vakata_dnd.is_drag) {
431
					if(
432
						Math.abs(e.pageX - vakata_dnd.init_x) > (vakata_dnd.is_touch ? $.vakata.dnd.settings.threshold_touch : $.vakata.dnd.settings.threshold) ||
433
						Math.abs(e.pageY - vakata_dnd.init_y) > (vakata_dnd.is_touch ? $.vakata.dnd.settings.threshold_touch : $.vakata.dnd.settings.threshold)
434
					) {
435
						if(vakata_dnd.helper) {
436
							vakata_dnd.helper.appendTo("body");
437
							vakata_dnd.helper_w = vakata_dnd.helper.outerWidth();
438
						}
439
						vakata_dnd.is_drag = true;
440
						/**
441
						 * triggered on the document when a drag starts
442
						 * @event
443
						 * @plugin dnd
444
						 * @name dnd_start.vakata
445
						 * @param {Mixed} data any data supplied with the call to $.vakata.dnd.start
446
						 * @param {DOM} element the DOM element being dragged
447
						 * @param {jQuery} helper the helper shown next to the mouse
448
						 * @param {Object} event the event that caused the start (probably mousemove)
449
						 */
450
						$.vakata.dnd._trigger("start", e);
451
					}
452
					else { return; }
453
				}
454
 
455
				var d  = false, w  = false,
456
					dh = false, wh = false,
457
					dw = false, ww = false,
458
					dt = false, dl = false,
459
					ht = false, hl = false;
460
 
461
				vakata_dnd.scroll_t = 0;
462
				vakata_dnd.scroll_l = 0;
463
				vakata_dnd.scroll_e = false;
464
				$($(e.target).parentsUntil("body").addBack().get().reverse())
465
					.filter(function () {
466
						return	(/^auto|scroll$/).test($(this).css("overflow")) &&
467
								(this.scrollHeight > this.offsetHeight || this.scrollWidth > this.offsetWidth);
468
					})
469
					.each(function () {
470
						var t = $(this), o = t.offset();
471
						if(this.scrollHeight > this.offsetHeight) {
472
							if(o.top + t.height() - e.pageY < $.vakata.dnd.settings.scroll_proximity)	{ vakata_dnd.scroll_t = 1; }
473
							if(e.pageY - o.top < $.vakata.dnd.settings.scroll_proximity)				{ vakata_dnd.scroll_t = -1; }
474
						}
475
						if(this.scrollWidth > this.offsetWidth) {
476
							if(o.left + t.width() - e.pageX < $.vakata.dnd.settings.scroll_proximity)	{ vakata_dnd.scroll_l = 1; }
477
							if(e.pageX - o.left < $.vakata.dnd.settings.scroll_proximity)				{ vakata_dnd.scroll_l = -1; }
478
						}
479
						if(vakata_dnd.scroll_t || vakata_dnd.scroll_l) {
480
							vakata_dnd.scroll_e = $(this);
481
							return false;
482
						}
483
					});
484
 
485
				if(!vakata_dnd.scroll_e) {
486
					d  = $(document); w = $(window);
487
					dh = d.height(); wh = w.height();
488
					dw = d.width(); ww = w.width();
489
					dt = d.scrollTop(); dl = d.scrollLeft();
490
					if(dh > wh && e.pageY - dt < $.vakata.dnd.settings.scroll_proximity)		{ vakata_dnd.scroll_t = -1;  }
491
					if(dh > wh && wh - (e.pageY - dt) < $.vakata.dnd.settings.scroll_proximity)	{ vakata_dnd.scroll_t = 1; }
492
					if(dw > ww && e.pageX - dl < $.vakata.dnd.settings.scroll_proximity)		{ vakata_dnd.scroll_l = -1; }
493
					if(dw > ww && ww - (e.pageX - dl) < $.vakata.dnd.settings.scroll_proximity)	{ vakata_dnd.scroll_l = 1; }
494
					if(vakata_dnd.scroll_t || vakata_dnd.scroll_l) {
495
						vakata_dnd.scroll_e = d;
496
					}
497
				}
498
				if(vakata_dnd.scroll_e) { $.vakata.dnd._scroll(true); }
499
 
500
				if(vakata_dnd.helper) {
501
					ht = parseInt(e.pageY + $.vakata.dnd.settings.helper_top, 10);
502
					hl = parseInt(e.pageX + $.vakata.dnd.settings.helper_left, 10);
503
					if(dh && ht + 25 > dh) { ht = dh - 50; }
504
					if(dw && hl + vakata_dnd.helper_w > dw) { hl = dw - (vakata_dnd.helper_w + 2); }
505
					vakata_dnd.helper.css({
506
						left	: hl + "px",
507
						top		: ht + "px"
508
					});
509
				}
510
				/**
511
				 * triggered on the document when a drag is in progress
512
				 * @event
513
				 * @plugin dnd
514
				 * @name dnd_move.vakata
515
				 * @param {Mixed} data any data supplied with the call to $.vakata.dnd.start
516
				 * @param {DOM} element the DOM element being dragged
517
				 * @param {jQuery} helper the helper shown next to the mouse
518
				 * @param {Object} event the event that caused this to trigger (most likely mousemove)
519
				 */
520
				$.vakata.dnd._trigger("move", e);
521
				return false;
522
			},
523
			stop : function (e) {
524
				if(e.type === "touchend" && e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0]) {
525
					e.pageX = e.originalEvent.changedTouches[0].pageX;
526
					e.pageY = e.originalEvent.changedTouches[0].pageY;
527
					e.target = document.elementFromPoint(e.originalEvent.changedTouches[0].pageX - window.pageXOffset, e.originalEvent.changedTouches[0].pageY - window.pageYOffset);
528
				}
529
				if(vakata_dnd.is_drag) {
530
					/**
531
					 * triggered on the document when a drag stops (the dragged element is dropped)
532
					 * @event
533
					 * @plugin dnd
534
					 * @name dnd_stop.vakata
535
					 * @param {Mixed} data any data supplied with the call to $.vakata.dnd.start
536
					 * @param {DOM} element the DOM element being dragged
537
					 * @param {jQuery} helper the helper shown next to the mouse
538
					 * @param {Object} event the event that caused the stop
539
					 */
540
					$.vakata.dnd._trigger("stop", e);
541
				}
542
				else {
543
					if(e.type === "touchend" && e.target === vakata_dnd.target) {
544
						var to = setTimeout(function () { $(e.target).click(); }, 100);
545
						$(e.target).one('click', function() { if(to) { clearTimeout(to); } });
546
					}
547
				}
548
				$.vakata.dnd._clean();
549
				return false;
550
			}
551
		};
552
	}($));
553
 
554
	// include the dnd plugin by default
555
	// $.jstree.defaults.plugins.push("dnd");
556
}));