Project

General

Profile

1
/*!
2
 * jQuery UI Draggable 1.9.1
3
 * http://jqueryui.com
4
 *
5
 * Copyright 2012 jQuery Foundation and other contributors
6
 * Released under the MIT license.
7
 * http://jquery.org/license
8
 *
9
 * http://api.jqueryui.com/draggable/
10
 *
11
 * Depends:
12
 *	jquery.ui.core.js
13
 *	jquery.ui.mouse.js
14
 *	jquery.ui.widget.js
15
 */
16
(function( $, undefined ) {
17

    
18
$.widget("ui.draggable", $.ui.mouse, {
19
	version: "1.9.1",
20
	widgetEventPrefix: "drag",
21
	options: {
22
		addClasses: true,
23
		appendTo: "parent",
24
		axis: false,
25
		connectToSortable: false,
26
		containment: false,
27
		cursor: "auto",
28
		cursorAt: false,
29
		grid: false,
30
		handle: false,
31
		helper: "original",
32
		iframeFix: false,
33
		opacity: false,
34
		refreshPositions: false,
35
		revert: false,
36
		revertDuration: 500,
37
		scope: "default",
38
		scroll: true,
39
		scrollSensitivity: 20,
40
		scrollSpeed: 20,
41
		snap: false,
42
		snapMode: "both",
43
		snapTolerance: 20,
44
		stack: false,
45
		zIndex: false
46
	},
47
	_create: function() {
48

    
49
		if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position")))
50
			this.element[0].style.position = 'relative';
51

    
52
		(this.options.addClasses && this.element.addClass("ui-draggable"));
53
		(this.options.disabled && this.element.addClass("ui-draggable-disabled"));
54

    
55
		this._mouseInit();
56

    
57
	},
58

    
59
	_destroy: function() {
60
		this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
61
		this._mouseDestroy();
62
	},
63

    
64
	_mouseCapture: function(event) {
65

    
66
		var o = this.options;
67

    
68
		// among others, prevent a drag on a resizable-handle
69
		if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle'))
70
			return false;
71

    
72
		//Quit if we're not on a valid handle
73
		this.handle = this._getHandle(event);
74
		if (!this.handle)
75
			return false;
76

    
77
		$(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
78
			$('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>')
79
			.css({
80
				width: this.offsetWidth+"px", height: this.offsetHeight+"px",
81
				position: "absolute", opacity: "0.001", zIndex: 1000
82
			})
83
			.css($(this).offset())
84
			.appendTo("body");
85
		});
86

    
87
		return true;
88

    
89
	},
90

    
91
	_mouseStart: function(event) {
92

    
93
		var o = this.options;
94

    
95
		//Create and append the visible helper
96
		this.helper = this._createHelper(event);
97

    
98
		this.helper.addClass("ui-draggable-dragging");
99

    
100
		//Cache the helper size
101
		this._cacheHelperProportions();
102

    
103
		//If ddmanager is used for droppables, set the global draggable
104
		if($.ui.ddmanager)
105
			$.ui.ddmanager.current = this;
106

    
107
		/*
108
		 * - Position generation -
109
		 * This block generates everything position related - it's the core of draggables.
110
		 */
111

    
112
		//Cache the margins of the original element
113
		this._cacheMargins();
114

    
115
		//Store the helper's css position
116
		this.cssPosition = this.helper.css("position");
117
		this.scrollParent = this.helper.scrollParent();
118

    
119
		//The element's absolute position on the page minus margins
120
		this.offset = this.positionAbs = this.element.offset();
121
		this.offset = {
122
			top: this.offset.top - this.margins.top,
123
			left: this.offset.left - this.margins.left
124
		};
125

    
126
		$.extend(this.offset, {
127
			click: { //Where the click happened, relative to the element
128
				left: event.pageX - this.offset.left,
129
				top: event.pageY - this.offset.top
130
			},
131
			parent: this._getParentOffset(),
132
			relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
133
		});
134

    
135
		//Generate the original position
136
		this.originalPosition = this.position = this._generatePosition(event);
137
		this.originalPageX = event.pageX;
138
		this.originalPageY = event.pageY;
139

    
140
		//Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
141
		(o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
142

    
143
		//Set a containment if given in the options
144
		if(o.containment)
145
			this._setContainment();
146

    
147
		//Trigger event + callbacks
148
		if(this._trigger("start", event) === false) {
149
			this._clear();
150
			return false;
151
		}
152

    
153
		//Recache the helper size
154
		this._cacheHelperProportions();
155

    
156
		//Prepare the droppable offsets
157
		if ($.ui.ddmanager && !o.dropBehaviour)
158
			$.ui.ddmanager.prepareOffsets(this, event);
159

    
160

    
161
		this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
162

    
163
		//If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
164
		if ( $.ui.ddmanager ) $.ui.ddmanager.dragStart(this, event);
165

    
166
		return true;
167
	},
168

    
169
	_mouseDrag: function(event, noPropagation) {
170

    
171
		//Compute the helpers position
172
		this.position = this._generatePosition(event);
173
		this.positionAbs = this._convertPositionTo("absolute");
174

    
175
		//Call plugins and callbacks and use the resulting position if something is returned
176
		if (!noPropagation) {
177
			var ui = this._uiHash();
178
			if(this._trigger('drag', event, ui) === false) {
179
				this._mouseUp({});
180
				return false;
181
			}
182
			this.position = ui.position;
183
		}
184

    
185
		if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
186
		if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
187
		if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
188

    
189
		return false;
190
	},
191

    
192
	_mouseStop: function(event) {
193

    
194
		//If we are using droppables, inform the manager about the drop
195
		var dropped = false;
196
		if ($.ui.ddmanager && !this.options.dropBehaviour)
197
			dropped = $.ui.ddmanager.drop(this, event);
198

    
199
		//if a drop comes from outside (a sortable)
200
		if(this.dropped) {
201
			dropped = this.dropped;
202
			this.dropped = false;
203
		}
204

    
205
		//if the original element is no longer in the DOM don't bother to continue (see #8269)
206
		var element = this.element[0], elementInDom = false;
207
		while ( element && (element = element.parentNode) ) {
208
			if (element == document ) {
209
				elementInDom = true;
210
			}
211
		}
212
		if ( !elementInDom && this.options.helper === "original" )
213
			return false;
214

    
215
		if((this.options.revert == "invalid" && !dropped) || (this.options.revert == "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) {
216
			var that = this;
217
			$(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
218
				if(that._trigger("stop", event) !== false) {
219
					that._clear();
220
				}
221
			});
222
		} else {
223
			if(this._trigger("stop", event) !== false) {
224
				this._clear();
225
			}
226
		}
227

    
228
		return false;
229
	},
230

    
231
	_mouseUp: function(event) {
232
		//Remove frame helpers
233
		$("div.ui-draggable-iframeFix").each(function() {
234
			this.parentNode.removeChild(this);
235
		});
236

    
237
		//If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
238
		if( $.ui.ddmanager ) $.ui.ddmanager.dragStop(this, event);
239

    
240
		return $.ui.mouse.prototype._mouseUp.call(this, event);
241
	},
242

    
243
	cancel: function() {
244

    
245
		if(this.helper.is(".ui-draggable-dragging")) {
246
			this._mouseUp({});
247
		} else {
248
			this._clear();
249
		}
250

    
251
		return this;
252

    
253
	},
254

    
255
	_getHandle: function(event) {
256

    
257
		var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false;
258
		$(this.options.handle, this.element)
259
			.find("*")
260
			.andSelf()
261
			.each(function() {
262
				if(this == event.target) handle = true;
263
			});
264

    
265
		return handle;
266

    
267
	},
268

    
269
	_createHelper: function(event) {
270

    
271
		var o = this.options;
272
		var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone().removeAttr('id') : this.element);
273

    
274
		if(!helper.parents('body').length)
275
			helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo));
276

    
277
		if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position")))
278
			helper.css("position", "absolute");
279

    
280
		return helper;
281

    
282
	},
283

    
284
	_adjustOffsetFromHelper: function(obj) {
285
		if (typeof obj == 'string') {
286
			obj = obj.split(' ');
287
		}
288
		if ($.isArray(obj)) {
289
			obj = {left: +obj[0], top: +obj[1] || 0};
290
		}
291
		if ('left' in obj) {
292
			this.offset.click.left = obj.left + this.margins.left;
293
		}
294
		if ('right' in obj) {
295
			this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
296
		}
297
		if ('top' in obj) {
298
			this.offset.click.top = obj.top + this.margins.top;
299
		}
300
		if ('bottom' in obj) {
301
			this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
302
		}
303
	},
304

    
305
	_getParentOffset: function() {
306

    
307
		//Get the offsetParent and cache its position
308
		this.offsetParent = this.helper.offsetParent();
309
		var po = this.offsetParent.offset();
310

    
311
		// This is a special case where we need to modify a offset calculated on start, since the following happened:
312
		// 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
313
		// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
314
		//    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
315
		if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
316
			po.left += this.scrollParent.scrollLeft();
317
			po.top += this.scrollParent.scrollTop();
318
		}
319

    
320
		if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
321
		|| (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.ui.ie)) //Ugly IE fix
322
			po = { top: 0, left: 0 };
323

    
324
		return {
325
			top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
326
			left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
327
		};
328

    
329
	},
330

    
331
	_getRelativeOffset: function() {
332

    
333
		if(this.cssPosition == "relative") {
334
			var p = this.element.position();
335
			return {
336
				top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
337
				left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
338
			};
339
		} else {
340
			return { top: 0, left: 0 };
341
		}
342

    
343
	},
344

    
345
	_cacheMargins: function() {
346
		this.margins = {
347
			left: (parseInt(this.element.css("marginLeft"),10) || 0),
348
			top: (parseInt(this.element.css("marginTop"),10) || 0),
349
			right: (parseInt(this.element.css("marginRight"),10) || 0),
350
			bottom: (parseInt(this.element.css("marginBottom"),10) || 0)
351
		};
352
	},
353

    
354
	_cacheHelperProportions: function() {
355
		this.helperProportions = {
356
			width: this.helper.outerWidth(),
357
			height: this.helper.outerHeight()
358
		};
359
	},
360

    
361
	_setContainment: function() {
362

    
363
		var o = this.options;
364
		if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
365
		if(o.containment == 'document' || o.containment == 'window') this.containment = [
366
			o.containment == 'document' ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
367
			o.containment == 'document' ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top,
368
			(o.containment == 'document' ? 0 : $(window).scrollLeft()) + $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
369
			(o.containment == 'document' ? 0 : $(window).scrollTop()) + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
370
		];
371

    
372
		if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) {
373
			var c = $(o.containment);
374
			var ce = c[0]; if(!ce) return;
375
			var co = c.offset();
376
			var over = ($(ce).css("overflow") != 'hidden');
377

    
378
			this.containment = [
379
				(parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0),
380
				(parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0),
381
				(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left - this.margins.right,
382
				(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top  - this.margins.bottom
383
			];
384
			this.relative_container = c;
385

    
386
		} else if(o.containment.constructor == Array) {
387
			this.containment = o.containment;
388
		}
389

    
390
	},
391

    
392
	_convertPositionTo: function(d, pos) {
393

    
394
		if(!pos) pos = this.position;
395
		var mod = d == "absolute" ? 1 : -1;
396
		var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
397

    
398
		return {
399
			top: (
400
				pos.top																	// The absolute mouse position
401
				+ this.offset.relative.top * mod										// Only for relative positioned nodes: Relative offset from element to offset parent
402
				+ this.offset.parent.top * mod											// The offsetParent's offset without borders (offset + border)
403
				- ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
404
			),
405
			left: (
406
				pos.left																// The absolute mouse position
407
				+ this.offset.relative.left * mod										// Only for relative positioned nodes: Relative offset from element to offset parent
408
				+ this.offset.parent.left * mod											// The offsetParent's offset without borders (offset + border)
409
				- ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
410
			)
411
		};
412

    
413
	},
414

    
415
	_generatePosition: function(event) {
416

    
417
		var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
418
		var pageX = event.pageX;
419
		var pageY = event.pageY;
420

    
421
		/*
422
		 * - Position constraining -
423
		 * Constrain the position to a mix of grid, containment.
424
		 */
425

    
426
		if(this.originalPosition) { //If we are not dragging yet, we won't check for options
427
			var containment;
428
			if(this.containment) {
429
			if (this.relative_container){
430
				var co = this.relative_container.offset();
431
				containment = [ this.containment[0] + co.left,
432
					this.containment[1] + co.top,
433
					this.containment[2] + co.left,
434
					this.containment[3] + co.top ];
435
			}
436
			else {
437
				containment = this.containment;
438
			}
439

    
440
				if(event.pageX - this.offset.click.left < containment[0]) pageX = containment[0] + this.offset.click.left;
441
				if(event.pageY - this.offset.click.top < containment[1]) pageY = containment[1] + this.offset.click.top;
442
				if(event.pageX - this.offset.click.left > containment[2]) pageX = containment[2] + this.offset.click.left;
443
				if(event.pageY - this.offset.click.top > containment[3]) pageY = containment[3] + this.offset.click.top;
444
			}
445

    
446
			if(o.grid) {
447
				//Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
448
				var top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
449
				pageY = containment ? (!(top - this.offset.click.top < containment[1] || top - this.offset.click.top > containment[3]) ? top : (!(top - this.offset.click.top < containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
450

    
451
				var left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
452
				pageX = containment ? (!(left - this.offset.click.left < containment[0] || left - this.offset.click.left > containment[2]) ? left : (!(left - this.offset.click.left < containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
453
			}
454

    
455
		}
456

    
457
		return {
458
			top: (
459
				pageY																// The absolute mouse position
460
				- this.offset.click.top													// Click offset (relative to the element)
461
				- this.offset.relative.top												// Only for relative positioned nodes: Relative offset from element to offset parent
462
				- this.offset.parent.top												// The offsetParent's offset without borders (offset + border)
463
				+ ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
464
			),
465
			left: (
466
				pageX																// The absolute mouse position
467
				- this.offset.click.left												// Click offset (relative to the element)
468
				- this.offset.relative.left												// Only for relative positioned nodes: Relative offset from element to offset parent
469
				- this.offset.parent.left												// The offsetParent's offset without borders (offset + border)
470
				+ ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
471
			)
472
		};
473

    
474
	},
475

    
476
	_clear: function() {
477
		this.helper.removeClass("ui-draggable-dragging");
478
		if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove();
479
		//if($.ui.ddmanager) $.ui.ddmanager.current = null;
480
		this.helper = null;
481
		this.cancelHelperRemoval = false;
482
	},
483

    
484
	// From now on bulk stuff - mainly helpers
485

    
486
	_trigger: function(type, event, ui) {
487
		ui = ui || this._uiHash();
488
		$.ui.plugin.call(this, type, [event, ui]);
489
		if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins
490
		return $.Widget.prototype._trigger.call(this, type, event, ui);
491
	},
492

    
493
	plugins: {},
494

    
495
	_uiHash: function(event) {
496
		return {
497
			helper: this.helper,
498
			position: this.position,
499
			originalPosition: this.originalPosition,
500
			offset: this.positionAbs
501
		};
502
	}
503

    
504
});
505

    
506
$.ui.plugin.add("draggable", "connectToSortable", {
507
	start: function(event, ui) {
508

    
509
		var inst = $(this).data("draggable"), o = inst.options,
510
			uiSortable = $.extend({}, ui, { item: inst.element });
511
		inst.sortables = [];
512
		$(o.connectToSortable).each(function() {
513
			var sortable = $.data(this, 'sortable');
514
			if (sortable && !sortable.options.disabled) {
515
				inst.sortables.push({
516
					instance: sortable,
517
					shouldRevert: sortable.options.revert
518
				});
519
				sortable.refreshPositions();	// Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page).
520
				sortable._trigger("activate", event, uiSortable);
521
			}
522
		});
523

    
524
	},
525
	stop: function(event, ui) {
526

    
527
		//If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
528
		var inst = $(this).data("draggable"),
529
			uiSortable = $.extend({}, ui, { item: inst.element });
530

    
531
		$.each(inst.sortables, function() {
532
			if(this.instance.isOver) {
533

    
534
				this.instance.isOver = 0;
535

    
536
				inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
537
				this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
538

    
539
				//The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid'
540
				if(this.shouldRevert) this.instance.options.revert = true;
541

    
542
				//Trigger the stop of the sortable
543
				this.instance._mouseStop(event);
544

    
545
				this.instance.options.helper = this.instance.options._helper;
546

    
547
				//If the helper has been the original item, restore properties in the sortable
548
				if(inst.options.helper == 'original')
549
					this.instance.currentItem.css({ top: 'auto', left: 'auto' });
550

    
551
			} else {
552
				this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
553
				this.instance._trigger("deactivate", event, uiSortable);
554
			}
555

    
556
		});
557

    
558
	},
559
	drag: function(event, ui) {
560

    
561
		var inst = $(this).data("draggable"), that = this;
562

    
563
		var checkPos = function(o) {
564
			var dyClick = this.offset.click.top, dxClick = this.offset.click.left;
565
			var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left;
566
			var itemHeight = o.height, itemWidth = o.width;
567
			var itemTop = o.top, itemLeft = o.left;
568

    
569
			return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth);
570
		};
571

    
572
		$.each(inst.sortables, function(i) {
573

    
574
			var innermostIntersecting = false;
575
			var thisSortable = this;
576
			//Copy over some variables to allow calling the sortable's native _intersectsWith
577
			this.instance.positionAbs = inst.positionAbs;
578
			this.instance.helperProportions = inst.helperProportions;
579
			this.instance.offset.click = inst.offset.click;
580

    
581
			if(this.instance._intersectsWith(this.instance.containerCache)) {
582
				innermostIntersecting = true;
583
				$.each(inst.sortables, function () {
584
					this.instance.positionAbs = inst.positionAbs;
585
					this.instance.helperProportions = inst.helperProportions;
586
					this.instance.offset.click = inst.offset.click;
587
					if  (this != thisSortable
588
						&& this.instance._intersectsWith(this.instance.containerCache)
589
						&& $.ui.contains(thisSortable.instance.element[0], this.instance.element[0]))
590
						innermostIntersecting = false;
591
						return innermostIntersecting;
592
				});
593
			}
594

    
595

    
596
			if(innermostIntersecting) {
597
				//If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
598
				if(!this.instance.isOver) {
599

    
600
					this.instance.isOver = 1;
601
					//Now we fake the start of dragging for the sortable instance,
602
					//by cloning the list group item, appending it to the sortable and using it as inst.currentItem
603
					//We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)
604
					this.instance.currentItem = $(that).clone().removeAttr('id').appendTo(this.instance.element).data("sortable-item", true);
605
					this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
606
					this.instance.options.helper = function() { return ui.helper[0]; };
607

    
608
					event.target = this.instance.currentItem[0];
609
					this.instance._mouseCapture(event, true);
610
					this.instance._mouseStart(event, true, true);
611

    
612
					//Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
613
					this.instance.offset.click.top = inst.offset.click.top;
614
					this.instance.offset.click.left = inst.offset.click.left;
615
					this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
616
					this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
617

    
618
					inst._trigger("toSortable", event);
619
					inst.dropped = this.instance.element; //draggable revert needs that
620
					//hack so receive/update callbacks work (mostly)
621
					inst.currentItem = inst.element;
622
					this.instance.fromOutside = inst;
623

    
624
				}
625

    
626
				//Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable
627
				if(this.instance.currentItem) this.instance._mouseDrag(event);
628

    
629
			} else {
630

    
631
				//If it doesn't intersect with the sortable, and it intersected before,
632
				//we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
633
				if(this.instance.isOver) {
634

    
635
					this.instance.isOver = 0;
636
					this.instance.cancelHelperRemoval = true;
637

    
638
					//Prevent reverting on this forced stop
639
					this.instance.options.revert = false;
640

    
641
					// The out event needs to be triggered independently
642
					this.instance._trigger('out', event, this.instance._uiHash(this.instance));
643

    
644
					this.instance._mouseStop(event, true);
645
					this.instance.options.helper = this.instance.options._helper;
646

    
647
					//Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
648
					this.instance.currentItem.remove();
649
					if(this.instance.placeholder) this.instance.placeholder.remove();
650

    
651
					inst._trigger("fromSortable", event);
652
					inst.dropped = false; //draggable revert needs that
653
				}
654

    
655
			};
656

    
657
		});
658

    
659
	}
660
});
661

    
662
$.ui.plugin.add("draggable", "cursor", {
663
	start: function(event, ui) {
664
		var t = $('body'), o = $(this).data('draggable').options;
665
		if (t.css("cursor")) o._cursor = t.css("cursor");
666
		t.css("cursor", o.cursor);
667
	},
668
	stop: function(event, ui) {
669
		var o = $(this).data('draggable').options;
670
		if (o._cursor) $('body').css("cursor", o._cursor);
671
	}
672
});
673

    
674
$.ui.plugin.add("draggable", "opacity", {
675
	start: function(event, ui) {
676
		var t = $(ui.helper), o = $(this).data('draggable').options;
677
		if(t.css("opacity")) o._opacity = t.css("opacity");
678
		t.css('opacity', o.opacity);
679
	},
680
	stop: function(event, ui) {
681
		var o = $(this).data('draggable').options;
682
		if(o._opacity) $(ui.helper).css('opacity', o._opacity);
683
	}
684
});
685

    
686
$.ui.plugin.add("draggable", "scroll", {
687
	start: function(event, ui) {
688
		var i = $(this).data("draggable");
689
		if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset();
690
	},
691
	drag: function(event, ui) {
692

    
693
		var i = $(this).data("draggable"), o = i.options, scrolled = false;
694

    
695
		if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') {
696

    
697
			if(!o.axis || o.axis != 'x') {
698
				if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
699
					i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
700
				else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity)
701
					i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
702
			}
703

    
704
			if(!o.axis || o.axis != 'y') {
705
				if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
706
					i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
707
				else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity)
708
					i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
709
			}
710

    
711
		} else {
712

    
713
			if(!o.axis || o.axis != 'x') {
714
				if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
715
					scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
716
				else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
717
					scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
718
			}
719

    
720
			if(!o.axis || o.axis != 'y') {
721
				if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
722
					scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
723
				else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
724
					scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
725
			}
726

    
727
		}
728

    
729
		if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
730
			$.ui.ddmanager.prepareOffsets(i, event);
731

    
732
	}
733
});
734

    
735
$.ui.plugin.add("draggable", "snap", {
736
	start: function(event, ui) {
737

    
738
		var i = $(this).data("draggable"), o = i.options;
739
		i.snapElements = [];
740

    
741
		$(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() {
742
			var $t = $(this); var $o = $t.offset();
743
			if(this != i.element[0]) i.snapElements.push({
744
				item: this,
745
				width: $t.outerWidth(), height: $t.outerHeight(),
746
				top: $o.top, left: $o.left
747
			});
748
		});
749

    
750
	},
751
	drag: function(event, ui) {
752

    
753
		var inst = $(this).data("draggable"), o = inst.options;
754
		var d = o.snapTolerance;
755

    
756
		var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
757
			y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
758

    
759
		for (var i = inst.snapElements.length - 1; i >= 0; i--){
760

    
761
			var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width,
762
				t = inst.snapElements[i].top, b = t + inst.snapElements[i].height;
763

    
764
			//Yes, I know, this is insane ;)
765
			if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) {
766
				if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
767
				inst.snapElements[i].snapping = false;
768
				continue;
769
			}
770

    
771
			if(o.snapMode != 'inner') {
772
				var ts = Math.abs(t - y2) <= d;
773
				var bs = Math.abs(b - y1) <= d;
774
				var ls = Math.abs(l - x2) <= d;
775
				var rs = Math.abs(r - x1) <= d;
776
				if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
777
				if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
778
				if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
779
				if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
780
			}
781

    
782
			var first = (ts || bs || ls || rs);
783

    
784
			if(o.snapMode != 'outer') {
785
				var ts = Math.abs(t - y1) <= d;
786
				var bs = Math.abs(b - y2) <= d;
787
				var ls = Math.abs(l - x1) <= d;
788
				var rs = Math.abs(r - x2) <= d;
789
				if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
790
				if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
791
				if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
792
				if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
793
			}
794

    
795
			if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first))
796
				(inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
797
			inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
798

    
799
		};
800

    
801
	}
802
});
803

    
804
$.ui.plugin.add("draggable", "stack", {
805
	start: function(event, ui) {
806

    
807
		var o = $(this).data("draggable").options;
808

    
809
		var group = $.makeArray($(o.stack)).sort(function(a,b) {
810
			return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
811
		});
812
		if (!group.length) { return; }
813

    
814
		var min = parseInt(group[0].style.zIndex) || 0;
815
		$(group).each(function(i) {
816
			this.style.zIndex = min + i;
817
		});
818

    
819
		this[0].style.zIndex = min + group.length;
820

    
821
	}
822
});
823

    
824
$.ui.plugin.add("draggable", "zIndex", {
825
	start: function(event, ui) {
826
		var t = $(ui.helper), o = $(this).data("draggable").options;
827
		if(t.css("zIndex")) o._zIndex = t.css("zIndex");
828
		t.css('zIndex', o.zIndex);
829
	},
830
	stop: function(event, ui) {
831
		var o = $(this).data("draggable").options;
832
		if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex);
833
	}
834
});
835

    
836
})(jQuery);
(8-8/35)