[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
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> </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 } );
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Thu Nov 21 08:20:01 2024 | Cross-referenced by PHPXref |