Diff: STRATO-apps/wordpress_03/app/wp-includes/js/jquery/ui/sortable.js

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