PluginProbe
RSVP and Event Management / 1.3.0
RSVP and Event Management v1.3.0
trunk 0.5.0 0.6.0 0.7.0 0.8.0 0.9.0 0.9.5 1.0.0 1.1.0 1.2.0 1.2.1 1.3.0 1.3.1 1.3.2 1.5.0 1.6.0 1.6.1 1.6.2 1.6.5 1.7.0 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 All 136 releases
rsvp / jquery-ui-1.7.2.custom / development-bundle / ui / ui.draggable.js

ui.draggable.js in RSVP and Event Management 1.3.0, at jquery-ui-1.7.2.custom/development-bundle/ui/ui.draggable.js

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