commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-old / civicrm / bower_components / jquery-ui / ui / draggable.js
1 /*!
2 * jQuery UI Draggable 1.11.4
3 * http://jqueryui.com
4 *
5 * Copyright 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 (function( factory ) {
12 if ( typeof define === "function" && define.amd ) {
13
14 // AMD. Register as an anonymous module.
15 define([
16 "jquery",
17 "./core",
18 "./mouse",
19 "./widget"
20 ], factory );
21 } else {
22
23 // Browser globals
24 factory( jQuery );
25 }
26 }(function( $ ) {
27
28 $.widget("ui.draggable", $.ui.mouse, {
29 version: "1.11.4",
30 widgetEventPrefix: "drag",
31 options: {
32 addClasses: true,
33 appendTo: "parent",
34 axis: false,
35 connectToSortable: false,
36 containment: false,
37 cursor: "auto",
38 cursorAt: false,
39 grid: false,
40 handle: false,
41 helper: "original",
42 iframeFix: false,
43 opacity: false,
44 refreshPositions: false,
45 revert: false,
46 revertDuration: 500,
47 scope: "default",
48 scroll: true,
49 scrollSensitivity: 20,
50 scrollSpeed: 20,
51 snap: false,
52 snapMode: "both",
53 snapTolerance: 20,
54 stack: false,
55 zIndex: false,
56
57 // callbacks
58 drag: null,
59 start: null,
60 stop: null
61 },
62 _create: function() {
63
64 if ( this.options.helper === "original" ) {
65 this._setPositionRelative();
66 }
67 if (this.options.addClasses){
68 this.element.addClass("ui-draggable");
69 }
70 if (this.options.disabled){
71 this.element.addClass("ui-draggable-disabled");
72 }
73 this._setHandleClassName();
74
75 this._mouseInit();
76 },
77
78 _setOption: function( key, value ) {
79 this._super( key, value );
80 if ( key === "handle" ) {
81 this._removeHandleClassName();
82 this._setHandleClassName();
83 }
84 },
85
86 _destroy: function() {
87 if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
88 this.destroyOnClear = true;
89 return;
90 }
91 this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
92 this._removeHandleClassName();
93 this._mouseDestroy();
94 },
95
96 _mouseCapture: function(event) {
97 var o = this.options;
98
99 this._blurActiveElement( event );
100
101 // among others, prevent a drag on a resizable-handle
102 if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
103 return false;
104 }
105
106 //Quit if we're not on a valid handle
107 this.handle = this._getHandle(event);
108 if (!this.handle) {
109 return false;
110 }
111
112 this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );
113
114 return true;
115
116 },
117
118 _blockFrames: function( selector ) {
119 this.iframeBlocks = this.document.find( selector ).map(function() {
120 var iframe = $( this );
121
122 return $( "<div>" )
123 .css( "position", "absolute" )
124 .appendTo( iframe.parent() )
125 .outerWidth( iframe.outerWidth() )
126 .outerHeight( iframe.outerHeight() )
127 .offset( iframe.offset() )[ 0 ];
128 });
129 },
130
131 _unblockFrames: function() {
132 if ( this.iframeBlocks ) {
133 this.iframeBlocks.remove();
134 delete this.iframeBlocks;
135 }
136 },
137
138 _blurActiveElement: function( event ) {
139 var document = this.document[ 0 ];
140
141 // Only need to blur if the event occurred on the draggable itself, see #10527
142 if ( !this.handleElement.is( event.target ) ) {
143 return;
144 }
145
146 // support: IE9
147 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
148 try {
149
150 // Support: IE9, IE10
151 // If the <body> is blurred, IE will switch windows, see #9520
152 if ( document.activeElement && document.activeElement.nodeName.toLowerCase() !== "body" ) {
153
154 // Blur any element that currently has focus, see #4261
155 $( document.activeElement ).blur();
156 }
157 } catch ( error ) {}
158 },
159
160 _mouseStart: function(event) {
161
162 var o = this.options;
163
164 //Create and append the visible helper
165 this.helper = this._createHelper(event);
166
167 this.helper.addClass("ui-draggable-dragging");
168
169 //Cache the helper size
170 this._cacheHelperProportions();
171
172 //If ddmanager is used for droppables, set the global draggable
173 if ($.ui.ddmanager) {
174 $.ui.ddmanager.current = this;
175 }
176
177 /*
178 * - Position generation -
179 * This block generates everything position related - it's the core of draggables.
180 */
181
182 //Cache the margins of the original element
183 this._cacheMargins();
184
185 //Store the helper's css position
186 this.cssPosition = this.helper.css( "position" );
187 this.scrollParent = this.helper.scrollParent( true );
188 this.offsetParent = this.helper.offsetParent();
189 this.hasFixedAncestor = this.helper.parents().filter(function() {
190 return $( this ).css( "position" ) === "fixed";
191 }).length > 0;
192
193 //The element's absolute position on the page minus margins
194 this.positionAbs = this.element.offset();
195 this._refreshOffsets( event );
196
197 //Generate the original position
198 this.originalPosition = this.position = this._generatePosition( event, false );
199 this.originalPageX = event.pageX;
200 this.originalPageY = event.pageY;
201
202 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
203 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
204
205 //Set a containment if given in the options
206 this._setContainment();
207
208 //Trigger event + callbacks
209 if (this._trigger("start", event) === false) {
210 this._clear();
211 return false;
212 }
213
214 //Recache the helper size
215 this._cacheHelperProportions();
216
217 //Prepare the droppable offsets
218 if ($.ui.ddmanager && !o.dropBehaviour) {
219 $.ui.ddmanager.prepareOffsets(this, event);
220 }
221
222 // Reset helper's right/bottom css if they're set and set explicit width/height instead
223 // as this prevents resizing of elements with right/bottom set (see #7772)
224 this._normalizeRightBottom();
225
226 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
227
228 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
229 if ( $.ui.ddmanager ) {
230 $.ui.ddmanager.dragStart(this, event);
231 }
232
233 return true;
234 },
235
236 _refreshOffsets: function( event ) {
237 this.offset = {
238 top: this.positionAbs.top - this.margins.top,
239 left: this.positionAbs.left - this.margins.left,
240 scroll: false,
241 parent: this._getParentOffset(),
242 relative: this._getRelativeOffset()
243 };
244
245 this.offset.click = {
246 left: event.pageX - this.offset.left,
247 top: event.pageY - this.offset.top
248 };
249 },
250
251 _mouseDrag: function(event, noPropagation) {
252 // reset any necessary cached properties (see #5009)
253 if ( this.hasFixedAncestor ) {
254 this.offset.parent = this._getParentOffset();
255 }
256
257 //Compute the helpers position
258 this.position = this._generatePosition( event, true );
259 this.positionAbs = this._convertPositionTo("absolute");
260
261 //Call plugins and callbacks and use the resulting position if something is returned
262 if (!noPropagation) {
263 var ui = this._uiHash();
264 if (this._trigger("drag", event, ui) === false) {
265 this._mouseUp({});
266 return false;
267 }
268 this.position = ui.position;
269 }
270
271 this.helper[ 0 ].style.left = this.position.left + "px";
272 this.helper[ 0 ].style.top = this.position.top + "px";
273
274 if ($.ui.ddmanager) {
275 $.ui.ddmanager.drag(this, event);
276 }
277
278 return false;
279 },
280
281 _mouseStop: function(event) {
282
283 //If we are using droppables, inform the manager about the drop
284 var that = this,
285 dropped = false;
286 if ($.ui.ddmanager && !this.options.dropBehaviour) {
287 dropped = $.ui.ddmanager.drop(this, event);
288 }
289
290 //if a drop comes from outside (a sortable)
291 if (this.dropped) {
292 dropped = this.dropped;
293 this.dropped = false;
294 }
295
296 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))) {
297 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
298 if (that._trigger("stop", event) !== false) {
299 that._clear();
300 }
301 });
302 } else {
303 if (this._trigger("stop", event) !== false) {
304 this._clear();
305 }
306 }
307
308 return false;
309 },
310
311 _mouseUp: function( event ) {
312 this._unblockFrames();
313
314 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
315 if ( $.ui.ddmanager ) {
316 $.ui.ddmanager.dragStop(this, event);
317 }
318
319 // Only need to focus if the event occurred on the draggable itself, see #10527
320 if ( this.handleElement.is( event.target ) ) {
321 // The interaction is over; whether or not the click resulted in a drag, focus the element
322 this.element.focus();
323 }
324
325 return $.ui.mouse.prototype._mouseUp.call(this, event);
326 },
327
328 cancel: function() {
329
330 if (this.helper.is(".ui-draggable-dragging")) {
331 this._mouseUp({});
332 } else {
333 this._clear();
334 }
335
336 return this;
337
338 },
339
340 _getHandle: function(event) {
341 return this.options.handle ?
342 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
343 true;
344 },
345
346 _setHandleClassName: function() {
347 this.handleElement = this.options.handle ?
348 this.element.find( this.options.handle ) : this.element;
349 this.handleElement.addClass( "ui-draggable-handle" );
350 },
351
352 _removeHandleClassName: function() {
353 this.handleElement.removeClass( "ui-draggable-handle" );
354 },
355
356 _createHelper: function(event) {
357
358 var o = this.options,
359 helperIsFunction = $.isFunction( o.helper ),
360 helper = helperIsFunction ?
361 $( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
362 ( o.helper === "clone" ?
363 this.element.clone().removeAttr( "id" ) :
364 this.element );
365
366 if (!helper.parents("body").length) {
367 helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
368 }
369
370 // http://bugs.jqueryui.com/ticket/9446
371 // a helper function can return the original element
372 // which wouldn't have been set to relative in _create
373 if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
374 this._setPositionRelative();
375 }
376
377 if (helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
378 helper.css("position", "absolute");
379 }
380
381 return helper;
382
383 },
384
385 _setPositionRelative: function() {
386 if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
387 this.element[ 0 ].style.position = "relative";
388 }
389 },
390
391 _adjustOffsetFromHelper: function(obj) {
392 if (typeof obj === "string") {
393 obj = obj.split(" ");
394 }
395 if ($.isArray(obj)) {
396 obj = { left: +obj[0], top: +obj[1] || 0 };
397 }
398 if ("left" in obj) {
399 this.offset.click.left = obj.left + this.margins.left;
400 }
401 if ("right" in obj) {
402 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
403 }
404 if ("top" in obj) {
405 this.offset.click.top = obj.top + this.margins.top;
406 }
407 if ("bottom" in obj) {
408 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
409 }
410 },
411
412 _isRootNode: function( element ) {
413 return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
414 },
415
416 _getParentOffset: function() {
417
418 //Get the offsetParent and cache its position
419 var po = this.offsetParent.offset(),
420 document = this.document[ 0 ];
421
422 // This is a special case where we need to modify a offset calculated on start, since the following happened:
423 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
424 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
425 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
426 if (this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
427 po.left += this.scrollParent.scrollLeft();
428 po.top += this.scrollParent.scrollTop();
429 }
430
431 if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
432 po = { top: 0, left: 0 };
433 }
434
435 return {
436 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"), 10) || 0),
437 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"), 10) || 0)
438 };
439
440 },
441
442 _getRelativeOffset: function() {
443 if ( this.cssPosition !== "relative" ) {
444 return { top: 0, left: 0 };
445 }
446
447 var p = this.element.position(),
448 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
449
450 return {
451 top: p.top - ( parseInt(this.helper.css( "top" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
452 left: p.left - ( parseInt(this.helper.css( "left" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
453 };
454
455 },
456
457 _cacheMargins: function() {
458 this.margins = {
459 left: (parseInt(this.element.css("marginLeft"), 10) || 0),
460 top: (parseInt(this.element.css("marginTop"), 10) || 0),
461 right: (parseInt(this.element.css("marginRight"), 10) || 0),
462 bottom: (parseInt(this.element.css("marginBottom"), 10) || 0)
463 };
464 },
465
466 _cacheHelperProportions: function() {
467 this.helperProportions = {
468 width: this.helper.outerWidth(),
469 height: this.helper.outerHeight()
470 };
471 },
472
473 _setContainment: function() {
474
475 var isUserScrollable, c, ce,
476 o = this.options,
477 document = this.document[ 0 ];
478
479 this.relativeContainer = null;
480
481 if ( !o.containment ) {
482 this.containment = null;
483 return;
484 }
485
486 if ( o.containment === "window" ) {
487 this.containment = [
488 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
489 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
490 $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left,
491 $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
492 ];
493 return;
494 }
495
496 if ( o.containment === "document") {
497 this.containment = [
498 0,
499 0,
500 $( document ).width() - this.helperProportions.width - this.margins.left,
501 ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
502 ];
503 return;
504 }
505
506 if ( o.containment.constructor === Array ) {
507 this.containment = o.containment;
508 return;
509 }
510
511 if ( o.containment === "parent" ) {
512 o.containment = this.helper[ 0 ].parentNode;
513 }
514
515 c = $( o.containment );
516 ce = c[ 0 ];
517
518 if ( !ce ) {
519 return;
520 }
521
522 isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );
523
524 this.containment = [
525 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
526 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
527 ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
528 ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
529 ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
530 this.helperProportions.width -
531 this.margins.left -
532 this.margins.right,
533 ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
534 ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
535 ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
536 this.helperProportions.height -
537 this.margins.top -
538 this.margins.bottom
539 ];
540 this.relativeContainer = c;
541 },
542
543 _convertPositionTo: function(d, pos) {
544
545 if (!pos) {
546 pos = this.position;
547 }
548
549 var mod = d === "absolute" ? 1 : -1,
550 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
551
552 return {
553 top: (
554 pos.top + // The absolute mouse position
555 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
556 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
557 ( ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod)
558 ),
559 left: (
560 pos.left + // The absolute mouse position
561 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
562 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
563 ( ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod)
564 )
565 };
566
567 },
568
569 _generatePosition: function( event, constrainPosition ) {
570
571 var containment, co, top, left,
572 o = this.options,
573 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
574 pageX = event.pageX,
575 pageY = event.pageY;
576
577 // Cache the scroll
578 if ( !scrollIsRootNode || !this.offset.scroll ) {
579 this.offset.scroll = {
580 top: this.scrollParent.scrollTop(),
581 left: this.scrollParent.scrollLeft()
582 };
583 }
584
585 /*
586 * - Position constraining -
587 * Constrain the position to a mix of grid, containment.
588 */
589
590 // If we are not dragging yet, we won't check for options
591 if ( constrainPosition ) {
592 if ( this.containment ) {
593 if ( this.relativeContainer ){
594 co = this.relativeContainer.offset();
595 containment = [
596 this.containment[ 0 ] + co.left,
597 this.containment[ 1 ] + co.top,
598 this.containment[ 2 ] + co.left,
599 this.containment[ 3 ] + co.top
600 ];
601 } else {
602 containment = this.containment;
603 }
604
605 if (event.pageX - this.offset.click.left < containment[0]) {
606 pageX = containment[0] + this.offset.click.left;
607 }
608 if (event.pageY - this.offset.click.top < containment[1]) {
609 pageY = containment[1] + this.offset.click.top;
610 }
611 if (event.pageX - this.offset.click.left > containment[2]) {
612 pageX = containment[2] + this.offset.click.left;
613 }
614 if (event.pageY - this.offset.click.top > containment[3]) {
615 pageY = containment[3] + this.offset.click.top;
616 }
617 }
618
619 if (o.grid) {
620 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
621 top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
622 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;
623
624 left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
625 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;
626 }
627
628 if ( o.axis === "y" ) {
629 pageX = this.originalPageX;
630 }
631
632 if ( o.axis === "x" ) {
633 pageY = this.originalPageY;
634 }
635 }
636
637 return {
638 top: (
639 pageY - // The absolute mouse position
640 this.offset.click.top - // Click offset (relative to the element)
641 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
642 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
643 ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
644 ),
645 left: (
646 pageX - // The absolute mouse position
647 this.offset.click.left - // Click offset (relative to the element)
648 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
649 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
650 ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
651 )
652 };
653
654 },
655
656 _clear: function() {
657 this.helper.removeClass("ui-draggable-dragging");
658 if (this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
659 this.helper.remove();
660 }
661 this.helper = null;
662 this.cancelHelperRemoval = false;
663 if ( this.destroyOnClear ) {
664 this.destroy();
665 }
666 },
667
668 _normalizeRightBottom: function() {
669 if ( this.options.axis !== "y" && this.helper.css( "right" ) !== "auto" ) {
670 this.helper.width( this.helper.width() );
671 this.helper.css( "right", "auto" );
672 }
673 if ( this.options.axis !== "x" && this.helper.css( "bottom" ) !== "auto" ) {
674 this.helper.height( this.helper.height() );
675 this.helper.css( "bottom", "auto" );
676 }
677 },
678
679 // From now on bulk stuff - mainly helpers
680
681 _trigger: function( type, event, ui ) {
682 ui = ui || this._uiHash();
683 $.ui.plugin.call( this, type, [ event, ui, this ], true );
684
685 // Absolute position and offset (see #6884 ) have to be recalculated after plugins
686 if ( /^(drag|start|stop)/.test( type ) ) {
687 this.positionAbs = this._convertPositionTo( "absolute" );
688 ui.offset = this.positionAbs;
689 }
690 return $.Widget.prototype._trigger.call( this, type, event, ui );
691 },
692
693 plugins: {},
694
695 _uiHash: function() {
696 return {
697 helper: this.helper,
698 position: this.position,
699 originalPosition: this.originalPosition,
700 offset: this.positionAbs
701 };
702 }
703
704 });
705
706 $.ui.plugin.add( "draggable", "connectToSortable", {
707 start: function( event, ui, draggable ) {
708 var uiSortable = $.extend( {}, ui, {
709 item: draggable.element
710 });
711
712 draggable.sortables = [];
713 $( draggable.options.connectToSortable ).each(function() {
714 var sortable = $( this ).sortable( "instance" );
715
716 if ( sortable && !sortable.options.disabled ) {
717 draggable.sortables.push( sortable );
718
719 // refreshPositions is called at drag start to refresh the containerCache
720 // which is used in drag. This ensures it's initialized and synchronized
721 // with any changes that might have happened on the page since initialization.
722 sortable.refreshPositions();
723 sortable._trigger("activate", event, uiSortable);
724 }
725 });
726 },
727 stop: function( event, ui, draggable ) {
728 var uiSortable = $.extend( {}, ui, {
729 item: draggable.element
730 });
731
732 draggable.cancelHelperRemoval = false;
733
734 $.each( draggable.sortables, function() {
735 var sortable = this;
736
737 if ( sortable.isOver ) {
738 sortable.isOver = 0;
739
740 // Allow this sortable to handle removing the helper
741 draggable.cancelHelperRemoval = true;
742 sortable.cancelHelperRemoval = false;
743
744 // Use _storedCSS To restore properties in the sortable,
745 // as this also handles revert (#9675) since the draggable
746 // may have modified them in unexpected ways (#8809)
747 sortable._storedCSS = {
748 position: sortable.placeholder.css( "position" ),
749 top: sortable.placeholder.css( "top" ),
750 left: sortable.placeholder.css( "left" )
751 };
752
753 sortable._mouseStop(event);
754
755 // Once drag has ended, the sortable should return to using
756 // its original helper, not the shared helper from draggable
757 sortable.options.helper = sortable.options._helper;
758 } else {
759 // Prevent this Sortable from removing the helper.
760 // However, don't set the draggable to remove the helper
761 // either as another connected Sortable may yet handle the removal.
762 sortable.cancelHelperRemoval = true;
763
764 sortable._trigger( "deactivate", event, uiSortable );
765 }
766 });
767 },
768 drag: function( event, ui, draggable ) {
769 $.each( draggable.sortables, function() {
770 var innermostIntersecting = false,
771 sortable = this;
772
773 // Copy over variables that sortable's _intersectsWith uses
774 sortable.positionAbs = draggable.positionAbs;
775 sortable.helperProportions = draggable.helperProportions;
776 sortable.offset.click = draggable.offset.click;
777
778 if ( sortable._intersectsWith( sortable.containerCache ) ) {
779 innermostIntersecting = true;
780
781 $.each( draggable.sortables, function() {
782 // Copy over variables that sortable's _intersectsWith uses
783 this.positionAbs = draggable.positionAbs;
784 this.helperProportions = draggable.helperProportions;
785 this.offset.click = draggable.offset.click;
786
787 if ( this !== sortable &&
788 this._intersectsWith( this.containerCache ) &&
789 $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
790 innermostIntersecting = false;
791 }
792
793 return innermostIntersecting;
794 });
795 }
796
797 if ( innermostIntersecting ) {
798 // If it intersects, we use a little isOver variable and set it once,
799 // so that the move-in stuff gets fired only once.
800 if ( !sortable.isOver ) {
801 sortable.isOver = 1;
802
803 // Store draggable's parent in case we need to reappend to it later.
804 draggable._parent = ui.helper.parent();
805
806 sortable.currentItem = ui.helper
807 .appendTo( sortable.element )
808 .data( "ui-sortable-item", true );
809
810 // Store helper option to later restore it
811 sortable.options._helper = sortable.options.helper;
812
813 sortable.options.helper = function() {
814 return ui.helper[ 0 ];
815 };
816
817 // Fire the start events of the sortable with our passed browser event,
818 // and our own helper (so it doesn't create a new one)
819 event.target = sortable.currentItem[ 0 ];
820 sortable._mouseCapture( event, true );
821 sortable._mouseStart( event, true, true );
822
823 // Because the browser event is way off the new appended portlet,
824 // modify necessary variables to reflect the changes
825 sortable.offset.click.top = draggable.offset.click.top;
826 sortable.offset.click.left = draggable.offset.click.left;
827 sortable.offset.parent.left -= draggable.offset.parent.left -
828 sortable.offset.parent.left;
829 sortable.offset.parent.top -= draggable.offset.parent.top -
830 sortable.offset.parent.top;
831
832 draggable._trigger( "toSortable", event );
833
834 // Inform draggable that the helper is in a valid drop zone,
835 // used solely in the revert option to handle "valid/invalid".
836 draggable.dropped = sortable.element;
837
838 // Need to refreshPositions of all sortables in the case that
839 // adding to one sortable changes the location of the other sortables (#9675)
840 $.each( draggable.sortables, function() {
841 this.refreshPositions();
842 });
843
844 // hack so receive/update callbacks work (mostly)
845 draggable.currentItem = draggable.element;
846 sortable.fromOutside = draggable;
847 }
848
849 if ( sortable.currentItem ) {
850 sortable._mouseDrag( event );
851 // Copy the sortable's position because the draggable's can potentially reflect
852 // a relative position, while sortable is always absolute, which the dragged
853 // element has now become. (#8809)
854 ui.position = sortable.position;
855 }
856 } else {
857 // If it doesn't intersect with the sortable, and it intersected before,
858 // we fake the drag stop of the sortable, but make sure it doesn't remove
859 // the helper by using cancelHelperRemoval.
860 if ( sortable.isOver ) {
861
862 sortable.isOver = 0;
863 sortable.cancelHelperRemoval = true;
864
865 // Calling sortable's mouseStop would trigger a revert,
866 // so revert must be temporarily false until after mouseStop is called.
867 sortable.options._revert = sortable.options.revert;
868 sortable.options.revert = false;
869
870 sortable._trigger( "out", event, sortable._uiHash( sortable ) );
871 sortable._mouseStop( event, true );
872
873 // restore sortable behaviors that were modfied
874 // when the draggable entered the sortable area (#9481)
875 sortable.options.revert = sortable.options._revert;
876 sortable.options.helper = sortable.options._helper;
877
878 if ( sortable.placeholder ) {
879 sortable.placeholder.remove();
880 }
881
882 // Restore and recalculate the draggable's offset considering the sortable
883 // may have modified them in unexpected ways. (#8809, #10669)
884 ui.helper.appendTo( draggable._parent );
885 draggable._refreshOffsets( event );
886 ui.position = draggable._generatePosition( event, true );
887
888 draggable._trigger( "fromSortable", event );
889
890 // Inform draggable that the helper is no longer in a valid drop zone
891 draggable.dropped = false;
892
893 // Need to refreshPositions of all sortables just in case removing
894 // from one sortable changes the location of other sortables (#9675)
895 $.each( draggable.sortables, function() {
896 this.refreshPositions();
897 });
898 }
899 }
900 });
901 }
902 });
903
904 $.ui.plugin.add("draggable", "cursor", {
905 start: function( event, ui, instance ) {
906 var t = $( "body" ),
907 o = instance.options;
908
909 if (t.css("cursor")) {
910 o._cursor = t.css("cursor");
911 }
912 t.css("cursor", o.cursor);
913 },
914 stop: function( event, ui, instance ) {
915 var o = instance.options;
916 if (o._cursor) {
917 $("body").css("cursor", o._cursor);
918 }
919 }
920 });
921
922 $.ui.plugin.add("draggable", "opacity", {
923 start: function( event, ui, instance ) {
924 var t = $( ui.helper ),
925 o = instance.options;
926 if (t.css("opacity")) {
927 o._opacity = t.css("opacity");
928 }
929 t.css("opacity", o.opacity);
930 },
931 stop: function( event, ui, instance ) {
932 var o = instance.options;
933 if (o._opacity) {
934 $(ui.helper).css("opacity", o._opacity);
935 }
936 }
937 });
938
939 $.ui.plugin.add("draggable", "scroll", {
940 start: function( event, ui, i ) {
941 if ( !i.scrollParentNotHidden ) {
942 i.scrollParentNotHidden = i.helper.scrollParent( false );
943 }
944
945 if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] && i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
946 i.overflowOffset = i.scrollParentNotHidden.offset();
947 }
948 },
949 drag: function( event, ui, i ) {
950
951 var o = i.options,
952 scrolled = false,
953 scrollParent = i.scrollParentNotHidden[ 0 ],
954 document = i.document[ 0 ];
955
956 if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
957 if ( !o.axis || o.axis !== "x" ) {
958 if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY < o.scrollSensitivity ) {
959 scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
960 } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
961 scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
962 }
963 }
964
965 if ( !o.axis || o.axis !== "y" ) {
966 if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX < o.scrollSensitivity ) {
967 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
968 } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
969 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
970 }
971 }
972
973 } else {
974
975 if (!o.axis || o.axis !== "x") {
976 if (event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
977 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
978 } else if ($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
979 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
980 }
981 }
982
983 if (!o.axis || o.axis !== "y") {
984 if (event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
985 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
986 } else if ($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
987 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
988 }
989 }
990
991 }
992
993 if (scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
994 $.ui.ddmanager.prepareOffsets(i, event);
995 }
996
997 }
998 });
999
1000 $.ui.plugin.add("draggable", "snap", {
1001 start: function( event, ui, i ) {
1002
1003 var o = i.options;
1004
1005 i.snapElements = [];
1006
1007 $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
1008 var $t = $(this),
1009 $o = $t.offset();
1010 if (this !== i.element[0]) {
1011 i.snapElements.push({
1012 item: this,
1013 width: $t.outerWidth(), height: $t.outerHeight(),
1014 top: $o.top, left: $o.left
1015 });
1016 }
1017 });
1018
1019 },
1020 drag: function( event, ui, inst ) {
1021
1022 var ts, bs, ls, rs, l, r, t, b, i, first,
1023 o = inst.options,
1024 d = o.snapTolerance,
1025 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
1026 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
1027
1028 for (i = inst.snapElements.length - 1; i >= 0; i--){
1029
1030 l = inst.snapElements[i].left - inst.margins.left;
1031 r = l + inst.snapElements[i].width;
1032 t = inst.snapElements[i].top - inst.margins.top;
1033 b = t + inst.snapElements[i].height;
1034
1035 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
1036 if (inst.snapElements[i].snapping) {
1037 (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
1038 }
1039 inst.snapElements[i].snapping = false;
1040 continue;
1041 }
1042
1043 if (o.snapMode !== "inner") {
1044 ts = Math.abs(t - y2) <= d;
1045 bs = Math.abs(b - y1) <= d;
1046 ls = Math.abs(l - x2) <= d;
1047 rs = Math.abs(r - x1) <= d;
1048 if (ts) {
1049 ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top;
1050 }
1051 if (bs) {
1052 ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top;
1053 }
1054 if (ls) {
1055 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left;
1056 }
1057 if (rs) {
1058 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left;
1059 }
1060 }
1061
1062 first = (ts || bs || ls || rs);
1063
1064 if (o.snapMode !== "outer") {
1065 ts = Math.abs(t - y1) <= d;
1066 bs = Math.abs(b - y2) <= d;
1067 ls = Math.abs(l - x1) <= d;
1068 rs = Math.abs(r - x2) <= d;
1069 if (ts) {
1070 ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top;
1071 }
1072 if (bs) {
1073 ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top;
1074 }
1075 if (ls) {
1076 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left;
1077 }
1078 if (rs) {
1079 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left;
1080 }
1081 }
1082
1083 if (!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
1084 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
1085 }
1086 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
1087
1088 }
1089
1090 }
1091 });
1092
1093 $.ui.plugin.add("draggable", "stack", {
1094 start: function( event, ui, instance ) {
1095 var min,
1096 o = instance.options,
1097 group = $.makeArray($(o.stack)).sort(function(a, b) {
1098 return (parseInt($(a).css("zIndex"), 10) || 0) - (parseInt($(b).css("zIndex"), 10) || 0);
1099 });
1100
1101 if (!group.length) { return; }
1102
1103 min = parseInt($(group[0]).css("zIndex"), 10) || 0;
1104 $(group).each(function(i) {
1105 $(this).css("zIndex", min + i);
1106 });
1107 this.css("zIndex", (min + group.length));
1108 }
1109 });
1110
1111 $.ui.plugin.add("draggable", "zIndex", {
1112 start: function( event, ui, instance ) {
1113 var t = $( ui.helper ),
1114 o = instance.options;
1115
1116 if (t.css("zIndex")) {
1117 o._zIndex = t.css("zIndex");
1118 }
1119 t.css("zIndex", o.zIndex);
1120 },
1121 stop: function( event, ui, instance ) {
1122 var o = instance.options;
1123
1124 if (o._zIndex) {
1125 $(ui.helper).css("zIndex", o._zIndex);
1126 }
1127 }
1128 });
1129
1130 return $.ui.draggable;
1131
1132 }));