Merge "Add columns option to Special:PrefixIndex"
[lhc/web/wiklou.git] / resources / lib / jquery.ui / jquery.ui.draggable.js
1 /*!
2 * jQuery UI Draggable 1.8.24
3 *
4 * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
5 * Dual licensed under the MIT or GPL Version 2 licenses.
6 * http://jquery.org/license
7 *
8 * http://docs.jquery.com/UI/Draggables
9 *
10 * Depends:
11 * jquery.ui.core.js
12 * jquery.ui.mouse.js
13 * jquery.ui.widget.js
14 */
15 (function( $, undefined ) {
16
17 $.widget("ui.draggable", $.ui.mouse, {
18 widgetEventPrefix: "drag",
19 options: {
20 addClasses: true,
21 appendTo: "parent",
22 axis: false,
23 connectToSortable: false,
24 containment: false,
25 cursor: "auto",
26 cursorAt: false,
27 grid: false,
28 handle: false,
29 helper: "original",
30 iframeFix: false,
31 opacity: false,
32 refreshPositions: false,
33 revert: false,
34 revertDuration: 500,
35 scope: "default",
36 scroll: true,
37 scrollSensitivity: 20,
38 scrollSpeed: 20,
39 snap: false,
40 snapMode: "both",
41 snapTolerance: 20,
42 stack: false,
43 zIndex: false
44 },
45 _create: function() {
46
47 if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position")))
48 this.element[0].style.position = 'relative';
49
50 (this.options.addClasses && this.element.addClass("ui-draggable"));
51 (this.options.disabled && this.element.addClass("ui-draggable-disabled"));
52
53 this._mouseInit();
54
55 },
56
57 destroy: function() {
58 if(!this.element.data('draggable')) return;
59 this.element
60 .removeData("draggable")
61 .unbind(".draggable")
62 .removeClass("ui-draggable"
63 + " ui-draggable-dragging"
64 + " ui-draggable-disabled");
65 this._mouseDestroy();
66
67 return this;
68 },
69
70 _mouseCapture: function(event) {
71
72 var o = this.options;
73
74 // among others, prevent a drag on a resizable-handle
75 if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle'))
76 return false;
77
78 //Quit if we're not on a valid handle
79 this.handle = this._getHandle(event);
80 if (!this.handle)
81 return false;
82
83 if ( o.iframeFix ) {
84 $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
85 $('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>')
86 .css({
87 width: this.offsetWidth+"px", height: this.offsetHeight+"px",
88 position: "absolute", opacity: "0.001", zIndex: 1000
89 })
90 .css($(this).offset())
91 .appendTo("body");
92 });
93 }
94
95 return true;
96
97 },
98
99 _mouseStart: function(event) {
100
101 var o = this.options;
102
103 //Create and append the visible helper
104 this.helper = this._createHelper(event);
105
106 this.helper.addClass("ui-draggable-dragging");
107
108 //Cache the helper size
109 this._cacheHelperProportions();
110
111 //If ddmanager is used for droppables, set the global draggable
112 if($.ui.ddmanager)
113 $.ui.ddmanager.current = this;
114
115 /*
116 * - Position generation -
117 * This block generates everything position related - it's the core of draggables.
118 */
119
120 //Cache the margins of the original element
121 this._cacheMargins();
122
123 //Store the helper's css position
124 this.cssPosition = this.helper.css("position");
125 this.scrollParent = this.helper.scrollParent();
126
127 //The element's absolute position on the page minus margins
128 this.offset = this.positionAbs = this.element.offset();
129 this.offset = {
130 top: this.offset.top - this.margins.top,
131 left: this.offset.left - this.margins.left
132 };
133
134 $.extend(this.offset, {
135 click: { //Where the click happened, relative to the element
136 left: event.pageX - this.offset.left,
137 top: event.pageY - this.offset.top
138 },
139 parent: this._getParentOffset(),
140 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
141 });
142
143 //Generate the original position
144 this.originalPosition = this.position = this._generatePosition(event);
145 this.originalPageX = event.pageX;
146 this.originalPageY = event.pageY;
147
148 //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
149 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
150
151 //Set a containment if given in the options
152 if(o.containment)
153 this._setContainment();
154
155 //Trigger event + callbacks
156 if(this._trigger("start", event) === false) {
157 this._clear();
158 return false;
159 }
160
161 //Recache the helper size
162 this._cacheHelperProportions();
163
164 //Prepare the droppable offsets
165 if ($.ui.ddmanager && !o.dropBehaviour)
166 $.ui.ddmanager.prepareOffsets(this, event);
167
168
169 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
170
171 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
172 if ( $.ui.ddmanager ) $.ui.ddmanager.dragStart(this, event);
173
174 return true;
175 },
176
177 _mouseDrag: function(event, noPropagation) {
178
179 //Compute the helpers position
180 this.position = this._generatePosition(event);
181 this.positionAbs = this._convertPositionTo("absolute");
182
183 //Call plugins and callbacks and use the resulting position if something is returned
184 if (!noPropagation) {
185 var ui = this._uiHash();
186 if(this._trigger('drag', event, ui) === false) {
187 this._mouseUp({});
188 return false;
189 }
190 this.position = ui.position;
191 }
192
193 if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
194 if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
195 if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
196
197 return false;
198 },
199
200 _mouseStop: function(event) {
201
202 //If we are using droppables, inform the manager about the drop
203 var dropped = false;
204 if ($.ui.ddmanager && !this.options.dropBehaviour)
205 dropped = $.ui.ddmanager.drop(this, event);
206
207 //if a drop comes from outside (a sortable)
208 if(this.dropped) {
209 dropped = this.dropped;
210 this.dropped = false;
211 }
212
213 //if the original element is no longer in the DOM don't bother to continue (see #8269)
214 var element = this.element[0], elementInDom = false;
215 while ( element && (element = element.parentNode) ) {
216 if (element == document ) {
217 elementInDom = true;
218 }
219 }
220 if ( !elementInDom && this.options.helper === "original" )
221 return false;
222
223 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))) {
224 var self = this;
225 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
226 if(self._trigger("stop", event) !== false) {
227 self._clear();
228 }
229 });
230 } else {
231 if(this._trigger("stop", event) !== false) {
232 this._clear();
233 }
234 }
235
236 return false;
237 },
238
239 _mouseUp: function(event) {
240 //Remove frame helpers
241 $("div.ui-draggable-iframeFix").each(function() {
242 this.parentNode.removeChild(this);
243 });
244
245 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
246 if( $.ui.ddmanager ) $.ui.ddmanager.dragStop(this, event);
247
248 return $.ui.mouse.prototype._mouseUp.call(this, event);
249 },
250
251 cancel: function() {
252
253 if(this.helper.is(".ui-draggable-dragging")) {
254 this._mouseUp({});
255 } else {
256 this._clear();
257 }
258
259 return this;
260
261 },
262
263 _getHandle: function(event) {
264
265 var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false;
266 $(this.options.handle, this.element)
267 .find("*")
268 .andSelf()
269 .each(function() {
270 if(this == event.target) handle = true;
271 });
272
273 return handle;
274
275 },
276
277 _createHelper: function(event) {
278
279 var o = this.options;
280 var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone().removeAttr('id') : this.element);
281
282 if(!helper.parents('body').length)
283 helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo));
284
285 if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position")))
286 helper.css("position", "absolute");
287
288 return helper;
289
290 },
291
292 _adjustOffsetFromHelper: function(obj) {
293 if (typeof obj == 'string') {
294 obj = obj.split(' ');
295 }
296 if ($.isArray(obj)) {
297 obj = {left: +obj[0], top: +obj[1] || 0};
298 }
299 if ('left' in obj) {
300 this.offset.click.left = obj.left + this.margins.left;
301 }
302 if ('right' in obj) {
303 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
304 }
305 if ('top' in obj) {
306 this.offset.click.top = obj.top + this.margins.top;
307 }
308 if ('bottom' in obj) {
309 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
310 }
311 },
312
313 _getParentOffset: function() {
314
315 //Get the offsetParent and cache its position
316 this.offsetParent = this.helper.offsetParent();
317 var po = this.offsetParent.offset();
318
319 // This is a special case where we need to modify a offset calculated on start, since the following happened:
320 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
321 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
322 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
323 if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) {
324 po.left += this.scrollParent.scrollLeft();
325 po.top += this.scrollParent.scrollTop();
326 }
327
328 if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
329 || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix
330 po = { top: 0, left: 0 };
331
332 return {
333 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
334 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
335 };
336
337 },
338
339 _getRelativeOffset: function() {
340
341 if(this.cssPosition == "relative") {
342 var p = this.element.position();
343 return {
344 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
345 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
346 };
347 } else {
348 return { top: 0, left: 0 };
349 }
350
351 },
352
353 _cacheMargins: function() {
354 this.margins = {
355 left: (parseInt(this.element.css("marginLeft"),10) || 0),
356 top: (parseInt(this.element.css("marginTop"),10) || 0),
357 right: (parseInt(this.element.css("marginRight"),10) || 0),
358 bottom: (parseInt(this.element.css("marginBottom"),10) || 0)
359 };
360 },
361
362 _cacheHelperProportions: function() {
363 this.helperProportions = {
364 width: this.helper.outerWidth(),
365 height: this.helper.outerHeight()
366 };
367 },
368
369 _setContainment: function() {
370
371 var o = this.options;
372 if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
373 if(o.containment == 'document' || o.containment == 'window') this.containment = [
374 o.containment == 'document' ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
375 o.containment == 'document' ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top,
376 (o.containment == 'document' ? 0 : $(window).scrollLeft()) + $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
377 (o.containment == 'document' ? 0 : $(window).scrollTop()) + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
378 ];
379
380 if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) {
381 var c = $(o.containment);
382 var ce = c[0]; if(!ce) return;
383 var co = c.offset();
384 var over = ($(ce).css("overflow") != 'hidden');
385
386 this.containment = [
387 (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0),
388 (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0),
389 (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,
390 (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
391 ];
392 this.relative_container = c;
393
394 } else if(o.containment.constructor == Array) {
395 this.containment = o.containment;
396 }
397
398 },
399
400 _convertPositionTo: function(d, pos) {
401
402 if(!pos) pos = this.position;
403 var mod = d == "absolute" ? 1 : -1;
404 var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
405
406 return {
407 top: (
408 pos.top // The absolute mouse position
409 + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent
410 + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border)
411 - ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
412 ),
413 left: (
414 pos.left // The absolute mouse position
415 + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent
416 + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border)
417 - ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
418 )
419 };
420
421 },
422
423 _generatePosition: function(event) {
424
425 var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
426 var pageX = event.pageX;
427 var pageY = event.pageY;
428
429 /*
430 * - Position constraining -
431 * Constrain the position to a mix of grid, containment.
432 */
433
434 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
435 var containment;
436 if(this.containment) {
437 if (this.relative_container){
438 var co = this.relative_container.offset();
439 containment = [ this.containment[0] + co.left,
440 this.containment[1] + co.top,
441 this.containment[2] + co.left,
442 this.containment[3] + co.top ];
443 }
444 else {
445 containment = this.containment;
446 }
447
448 if(event.pageX - this.offset.click.left < containment[0]) pageX = containment[0] + this.offset.click.left;
449 if(event.pageY - this.offset.click.top < containment[1]) pageY = containment[1] + this.offset.click.top;
450 if(event.pageX - this.offset.click.left > containment[2]) pageX = containment[2] + this.offset.click.left;
451 if(event.pageY - this.offset.click.top > containment[3]) pageY = containment[3] + this.offset.click.top;
452 }
453
454 if(o.grid) {
455 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
456 var top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
457 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;
458
459 var left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
460 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;
461 }
462
463 }
464
465 return {
466 top: (
467 pageY // The absolute mouse position
468 - this.offset.click.top // Click offset (relative to the element)
469 - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent
470 - this.offset.parent.top // The offsetParent's offset without borders (offset + border)
471 + ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
472 ),
473 left: (
474 pageX // The absolute mouse position
475 - this.offset.click.left // Click offset (relative to the element)
476 - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent
477 - this.offset.parent.left // The offsetParent's offset without borders (offset + border)
478 + ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
479 )
480 };
481
482 },
483
484 _clear: function() {
485 this.helper.removeClass("ui-draggable-dragging");
486 if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove();
487 //if($.ui.ddmanager) $.ui.ddmanager.current = null;
488 this.helper = null;
489 this.cancelHelperRemoval = false;
490 },
491
492 // From now on bulk stuff - mainly helpers
493
494 _trigger: function(type, event, ui) {
495 ui = ui || this._uiHash();
496 $.ui.plugin.call(this, type, [event, ui]);
497 if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins
498 return $.Widget.prototype._trigger.call(this, type, event, ui);
499 },
500
501 plugins: {},
502
503 _uiHash: function(event) {
504 return {
505 helper: this.helper,
506 position: this.position,
507 originalPosition: this.originalPosition,
508 offset: this.positionAbs
509 };
510 }
511
512 });
513
514 $.extend($.ui.draggable, {
515 version: "1.8.24"
516 });
517
518 $.ui.plugin.add("draggable", "connectToSortable", {
519 start: function(event, ui) {
520
521 var inst = $(this).data("draggable"), o = inst.options,
522 uiSortable = $.extend({}, ui, { item: inst.element });
523 inst.sortables = [];
524 $(o.connectToSortable).each(function() {
525 var sortable = $.data(this, 'sortable');
526 if (sortable && !sortable.options.disabled) {
527 inst.sortables.push({
528 instance: sortable,
529 shouldRevert: sortable.options.revert
530 });
531 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).
532 sortable._trigger("activate", event, uiSortable);
533 }
534 });
535
536 },
537 stop: function(event, ui) {
538
539 //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
540 var inst = $(this).data("draggable"),
541 uiSortable = $.extend({}, ui, { item: inst.element });
542
543 $.each(inst.sortables, function() {
544 if(this.instance.isOver) {
545
546 this.instance.isOver = 0;
547
548 inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
549 this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
550
551 //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid'
552 if(this.shouldRevert) this.instance.options.revert = true;
553
554 //Trigger the stop of the sortable
555 this.instance._mouseStop(event);
556
557 this.instance.options.helper = this.instance.options._helper;
558
559 //If the helper has been the original item, restore properties in the sortable
560 if(inst.options.helper == 'original')
561 this.instance.currentItem.css({ top: 'auto', left: 'auto' });
562
563 } else {
564 this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
565 this.instance._trigger("deactivate", event, uiSortable);
566 }
567
568 });
569
570 },
571 drag: function(event, ui) {
572
573 var inst = $(this).data("draggable"), self = this;
574
575 var checkPos = function(o) {
576 var dyClick = this.offset.click.top, dxClick = this.offset.click.left;
577 var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left;
578 var itemHeight = o.height, itemWidth = o.width;
579 var itemTop = o.top, itemLeft = o.left;
580
581 return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth);
582 };
583
584 $.each(inst.sortables, function(i) {
585
586 //Copy over some variables to allow calling the sortable's native _intersectsWith
587 this.instance.positionAbs = inst.positionAbs;
588 this.instance.helperProportions = inst.helperProportions;
589 this.instance.offset.click = inst.offset.click;
590
591 if(this.instance._intersectsWith(this.instance.containerCache)) {
592
593 //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
594 if(!this.instance.isOver) {
595
596 this.instance.isOver = 1;
597 //Now we fake the start of dragging for the sortable instance,
598 //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
599 //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)
600 this.instance.currentItem = $(self).clone().removeAttr('id').appendTo(this.instance.element).data("sortable-item", true);
601 this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
602 this.instance.options.helper = function() { return ui.helper[0]; };
603
604 event.target = this.instance.currentItem[0];
605 this.instance._mouseCapture(event, true);
606 this.instance._mouseStart(event, true, true);
607
608 //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
609 this.instance.offset.click.top = inst.offset.click.top;
610 this.instance.offset.click.left = inst.offset.click.left;
611 this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
612 this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
613
614 inst._trigger("toSortable", event);
615 inst.dropped = this.instance.element; //draggable revert needs that
616 //hack so receive/update callbacks work (mostly)
617 inst.currentItem = inst.element;
618 this.instance.fromOutside = inst;
619
620 }
621
622 //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
623 if(this.instance.currentItem) this.instance._mouseDrag(event);
624
625 } else {
626
627 //If it doesn't intersect with the sortable, and it intersected before,
628 //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
629 if(this.instance.isOver) {
630
631 this.instance.isOver = 0;
632 this.instance.cancelHelperRemoval = true;
633
634 //Prevent reverting on this forced stop
635 this.instance.options.revert = false;
636
637 // The out event needs to be triggered independently
638 this.instance._trigger('out', event, this.instance._uiHash(this.instance));
639
640 this.instance._mouseStop(event, true);
641 this.instance.options.helper = this.instance.options._helper;
642
643 //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
644 this.instance.currentItem.remove();
645 if(this.instance.placeholder) this.instance.placeholder.remove();
646
647 inst._trigger("fromSortable", event);
648 inst.dropped = false; //draggable revert needs that
649 }
650
651 };
652
653 });
654
655 }
656 });
657
658 $.ui.plugin.add("draggable", "cursor", {
659 start: function(event, ui) {
660 var t = $('body'), o = $(this).data('draggable').options;
661 if (t.css("cursor")) o._cursor = t.css("cursor");
662 t.css("cursor", o.cursor);
663 },
664 stop: function(event, ui) {
665 var o = $(this).data('draggable').options;
666 if (o._cursor) $('body').css("cursor", o._cursor);
667 }
668 });
669
670 $.ui.plugin.add("draggable", "opacity", {
671 start: function(event, ui) {
672 var t = $(ui.helper), o = $(this).data('draggable').options;
673 if(t.css("opacity")) o._opacity = t.css("opacity");
674 t.css('opacity', o.opacity);
675 },
676 stop: function(event, ui) {
677 var o = $(this).data('draggable').options;
678 if(o._opacity) $(ui.helper).css('opacity', o._opacity);
679 }
680 });
681
682 $.ui.plugin.add("draggable", "scroll", {
683 start: function(event, ui) {
684 var i = $(this).data("draggable");
685 if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset();
686 },
687 drag: function(event, ui) {
688
689 var i = $(this).data("draggable"), o = i.options, scrolled = false;
690
691 if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') {
692
693 if(!o.axis || o.axis != 'x') {
694 if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
695 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
696 else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity)
697 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
698 }
699
700 if(!o.axis || o.axis != 'y') {
701 if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
702 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
703 else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity)
704 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
705 }
706
707 } else {
708
709 if(!o.axis || o.axis != 'x') {
710 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
711 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
712 else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
713 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
714 }
715
716 if(!o.axis || o.axis != 'y') {
717 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
718 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
719 else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
720 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
721 }
722
723 }
724
725 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
726 $.ui.ddmanager.prepareOffsets(i, event);
727
728 }
729 });
730
731 $.ui.plugin.add("draggable", "snap", {
732 start: function(event, ui) {
733
734 var i = $(this).data("draggable"), o = i.options;
735 i.snapElements = [];
736
737 $(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() {
738 var $t = $(this); var $o = $t.offset();
739 if(this != i.element[0]) i.snapElements.push({
740 item: this,
741 width: $t.outerWidth(), height: $t.outerHeight(),
742 top: $o.top, left: $o.left
743 });
744 });
745
746 },
747 drag: function(event, ui) {
748
749 var inst = $(this).data("draggable"), o = inst.options;
750 var d = o.snapTolerance;
751
752 var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
753 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
754
755 for (var i = inst.snapElements.length - 1; i >= 0; i--){
756
757 var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width,
758 t = inst.snapElements[i].top, b = t + inst.snapElements[i].height;
759
760 //Yes, I know, this is insane ;)
761 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))) {
762 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 })));
763 inst.snapElements[i].snapping = false;
764 continue;
765 }
766
767 if(o.snapMode != 'inner') {
768 var ts = Math.abs(t - y2) <= d;
769 var bs = Math.abs(b - y1) <= d;
770 var ls = Math.abs(l - x2) <= d;
771 var rs = Math.abs(r - x1) <= d;
772 if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
773 if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
774 if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
775 if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
776 }
777
778 var first = (ts || bs || ls || rs);
779
780 if(o.snapMode != 'outer') {
781 var ts = Math.abs(t - y1) <= d;
782 var bs = Math.abs(b - y2) <= d;
783 var ls = Math.abs(l - x1) <= d;
784 var rs = Math.abs(r - x2) <= d;
785 if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
786 if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
787 if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
788 if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
789 }
790
791 if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first))
792 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
793 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
794
795 };
796
797 }
798 });
799
800 $.ui.plugin.add("draggable", "stack", {
801 start: function(event, ui) {
802
803 var o = $(this).data("draggable").options;
804
805 var group = $.makeArray($(o.stack)).sort(function(a,b) {
806 return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
807 });
808 if (!group.length) { return; }
809
810 var min = parseInt(group[0].style.zIndex) || 0;
811 $(group).each(function(i) {
812 this.style.zIndex = min + i;
813 });
814
815 this[0].style.zIndex = min + group.length;
816
817 }
818 });
819
820 $.ui.plugin.add("draggable", "zIndex", {
821 start: function(event, ui) {
822 var t = $(ui.helper), o = $(this).data("draggable").options;
823 if(t.css("zIndex")) o._zIndex = t.css("zIndex");
824 t.css('zIndex', o.zIndex);
825 },
826 stop: function(event, ui) {
827 var o = $(this).data("draggable").options;
828 if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex);
829 }
830 });
831
832 })(jQuery);