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