[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/js/jquery/ui/ -> droppable.js (source)

   1  /*!
   2   * jQuery UI Droppable 1.13.2
   3   * http://jqueryui.com
   4   *
   5   * Copyright jQuery Foundation and other contributors
   6   * Released under the MIT license.
   7   * http://jquery.org/license
   8   */
   9  
  10  //>>label: Droppable
  11  //>>group: Interactions
  12  //>>description: Enables drop targets for draggable elements.
  13  //>>docs: http://api.jqueryui.com/droppable/
  14  //>>demos: http://jqueryui.com/droppable/
  15  
  16  ( function( factory ) {
  17      "use strict";
  18  
  19      if ( typeof define === "function" && define.amd ) {
  20  
  21          // AMD. Register as an anonymous module.
  22          define( [
  23              "jquery",
  24              "./draggable",
  25              "./mouse",
  26              "./core"
  27          ], factory );
  28      } else {
  29  
  30          // Browser globals
  31          factory( jQuery );
  32      }
  33  } )( function( $ ) {
  34  "use strict";
  35  
  36  $.widget( "ui.droppable", {
  37      version: "1.13.2",
  38      widgetEventPrefix: "drop",
  39      options: {
  40          accept: "*",
  41          addClasses: true,
  42          greedy: false,
  43          scope: "default",
  44          tolerance: "intersect",
  45  
  46          // Callbacks
  47          activate: null,
  48          deactivate: null,
  49          drop: null,
  50          out: null,
  51          over: null
  52      },
  53      _create: function() {
  54  
  55          var proportions,
  56              o = this.options,
  57              accept = o.accept;
  58  
  59          this.isover = false;
  60          this.isout = true;
  61  
  62          this.accept = typeof accept === "function" ? accept : function( d ) {
  63              return d.is( accept );
  64          };
  65  
  66          this.proportions = function( /* valueToWrite */ ) {
  67              if ( arguments.length ) {
  68  
  69                  // Store the droppable's proportions
  70                  proportions = arguments[ 0 ];
  71              } else {
  72  
  73                  // Retrieve or derive the droppable's proportions
  74                  return proportions ?
  75                      proportions :
  76                      proportions = {
  77                          width: this.element[ 0 ].offsetWidth,
  78                          height: this.element[ 0 ].offsetHeight
  79                      };
  80              }
  81          };
  82  
  83          this._addToManager( o.scope );
  84  
  85          if ( o.addClasses ) {
  86              this._addClass( "ui-droppable" );
  87          }
  88  
  89      },
  90  
  91      _addToManager: function( scope ) {
  92  
  93          // Add the reference and positions to the manager
  94          $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
  95          $.ui.ddmanager.droppables[ scope ].push( this );
  96      },
  97  
  98      _splice: function( drop ) {
  99          var i = 0;
 100          for ( ; i < drop.length; i++ ) {
 101              if ( drop[ i ] === this ) {
 102                  drop.splice( i, 1 );
 103              }
 104          }
 105      },
 106  
 107      _destroy: function() {
 108          var drop = $.ui.ddmanager.droppables[ this.options.scope ];
 109  
 110          this._splice( drop );
 111      },
 112  
 113      _setOption: function( key, value ) {
 114  
 115          if ( key === "accept" ) {
 116              this.accept = typeof value === "function" ? value : function( d ) {
 117                  return d.is( value );
 118              };
 119          } else if ( key === "scope" ) {
 120              var drop = $.ui.ddmanager.droppables[ this.options.scope ];
 121  
 122              this._splice( drop );
 123              this._addToManager( value );
 124          }
 125  
 126          this._super( key, value );
 127      },
 128  
 129      _activate: function( event ) {
 130          var draggable = $.ui.ddmanager.current;
 131  
 132          this._addActiveClass();
 133          if ( draggable ) {
 134              this._trigger( "activate", event, this.ui( draggable ) );
 135          }
 136      },
 137  
 138      _deactivate: function( event ) {
 139          var draggable = $.ui.ddmanager.current;
 140  
 141          this._removeActiveClass();
 142          if ( draggable ) {
 143              this._trigger( "deactivate", event, this.ui( draggable ) );
 144          }
 145      },
 146  
 147      _over: function( event ) {
 148  
 149          var draggable = $.ui.ddmanager.current;
 150  
 151          // Bail if draggable and droppable are same element
 152          if ( !draggable || ( draggable.currentItem ||
 153                  draggable.element )[ 0 ] === this.element[ 0 ] ) {
 154              return;
 155          }
 156  
 157          if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
 158                  draggable.element ) ) ) {
 159              this._addHoverClass();
 160              this._trigger( "over", event, this.ui( draggable ) );
 161          }
 162  
 163      },
 164  
 165      _out: function( event ) {
 166  
 167          var draggable = $.ui.ddmanager.current;
 168  
 169          // Bail if draggable and droppable are same element
 170          if ( !draggable || ( draggable.currentItem ||
 171                  draggable.element )[ 0 ] === this.element[ 0 ] ) {
 172              return;
 173          }
 174  
 175          if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
 176                  draggable.element ) ) ) {
 177              this._removeHoverClass();
 178              this._trigger( "out", event, this.ui( draggable ) );
 179          }
 180  
 181      },
 182  
 183      _drop: function( event, custom ) {
 184  
 185          var draggable = custom || $.ui.ddmanager.current,
 186              childrenIntersection = false;
 187  
 188          // Bail if draggable and droppable are same element
 189          if ( !draggable || ( draggable.currentItem ||
 190                  draggable.element )[ 0 ] === this.element[ 0 ] ) {
 191              return false;
 192          }
 193  
 194          this.element
 195              .find( ":data(ui-droppable)" )
 196              .not( ".ui-draggable-dragging" )
 197              .each( function() {
 198                  var inst = $( this ).droppable( "instance" );
 199                  if (
 200                      inst.options.greedy &&
 201                      !inst.options.disabled &&
 202                      inst.options.scope === draggable.options.scope &&
 203                      inst.accept.call(
 204                          inst.element[ 0 ], ( draggable.currentItem || draggable.element )
 205                      ) &&
 206                      $.ui.intersect(
 207                          draggable,
 208                          $.extend( inst, { offset: inst.element.offset() } ),
 209                          inst.options.tolerance, event
 210                      )
 211                  ) {
 212                      childrenIntersection = true;
 213                      return false;
 214                  }
 215              } );
 216          if ( childrenIntersection ) {
 217              return false;
 218          }
 219  
 220          if ( this.accept.call( this.element[ 0 ],
 221                  ( draggable.currentItem || draggable.element ) ) ) {
 222              this._removeActiveClass();
 223              this._removeHoverClass();
 224  
 225              this._trigger( "drop", event, this.ui( draggable ) );
 226              return this.element;
 227          }
 228  
 229          return false;
 230  
 231      },
 232  
 233      ui: function( c ) {
 234          return {
 235              draggable: ( c.currentItem || c.element ),
 236              helper: c.helper,
 237              position: c.position,
 238              offset: c.positionAbs
 239          };
 240      },
 241  
 242      // Extension points just to make backcompat sane and avoid duplicating logic
 243      // TODO: Remove in 1.14 along with call to it below
 244      _addHoverClass: function() {
 245          this._addClass( "ui-droppable-hover" );
 246      },
 247  
 248      _removeHoverClass: function() {
 249          this._removeClass( "ui-droppable-hover" );
 250      },
 251  
 252      _addActiveClass: function() {
 253          this._addClass( "ui-droppable-active" );
 254      },
 255  
 256      _removeActiveClass: function() {
 257          this._removeClass( "ui-droppable-active" );
 258      }
 259  } );
 260  
 261  $.ui.intersect = ( function() {
 262  	function isOverAxis( x, reference, size ) {
 263          return ( x >= reference ) && ( x < ( reference + size ) );
 264      }
 265  
 266      return function( draggable, droppable, toleranceMode, event ) {
 267  
 268          if ( !droppable.offset ) {
 269              return false;
 270          }
 271  
 272          var x1 = ( draggable.positionAbs ||
 273                  draggable.position.absolute ).left + draggable.margins.left,
 274              y1 = ( draggable.positionAbs ||
 275                  draggable.position.absolute ).top + draggable.margins.top,
 276              x2 = x1 + draggable.helperProportions.width,
 277              y2 = y1 + draggable.helperProportions.height,
 278              l = droppable.offset.left,
 279              t = droppable.offset.top,
 280              r = l + droppable.proportions().width,
 281              b = t + droppable.proportions().height;
 282  
 283          switch ( toleranceMode ) {
 284          case "fit":
 285              return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
 286          case "intersect":
 287              return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
 288                  x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
 289                  t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
 290                  y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
 291          case "pointer":
 292              return isOverAxis( event.pageY, t, droppable.proportions().height ) &&
 293                  isOverAxis( event.pageX, l, droppable.proportions().width );
 294          case "touch":
 295              return (
 296                  ( y1 >= t && y1 <= b ) || // Top edge touching
 297                  ( y2 >= t && y2 <= b ) || // Bottom edge touching
 298                  ( y1 < t && y2 > b ) // Surrounded vertically
 299              ) && (
 300                  ( x1 >= l && x1 <= r ) || // Left edge touching
 301                  ( x2 >= l && x2 <= r ) || // Right edge touching
 302                  ( x1 < l && x2 > r ) // Surrounded horizontally
 303              );
 304          default:
 305              return false;
 306          }
 307      };
 308  } )();
 309  
 310  /*
 311      This manager tracks offsets of draggables and droppables
 312  */
 313  $.ui.ddmanager = {
 314      current: null,
 315      droppables: { "default": [] },
 316      prepareOffsets: function( t, event ) {
 317  
 318          var i, j,
 319              m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
 320              type = event ? event.type : null, // workaround for #2317
 321              list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();
 322  
 323          droppablesLoop: for ( i = 0; i < m.length; i++ ) {
 324  
 325              // No disabled and non-accepted
 326              if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ],
 327                      ( t.currentItem || t.element ) ) ) ) {
 328                  continue;
 329              }
 330  
 331              // Filter out elements in the current dragged item
 332              for ( j = 0; j < list.length; j++ ) {
 333                  if ( list[ j ] === m[ i ].element[ 0 ] ) {
 334                      m[ i ].proportions().height = 0;
 335                      continue droppablesLoop;
 336                  }
 337              }
 338  
 339              m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
 340              if ( !m[ i ].visible ) {
 341                  continue;
 342              }
 343  
 344              // Activate the droppable if used directly from draggables
 345              if ( type === "mousedown" ) {
 346                  m[ i ]._activate.call( m[ i ], event );
 347              }
 348  
 349              m[ i ].offset = m[ i ].element.offset();
 350              m[ i ].proportions( {
 351                  width: m[ i ].element[ 0 ].offsetWidth,
 352                  height: m[ i ].element[ 0 ].offsetHeight
 353              } );
 354  
 355          }
 356  
 357      },
 358      drop: function( draggable, event ) {
 359  
 360          var dropped = false;
 361  
 362          // Create a copy of the droppables in case the list changes during the drop (#9116)
 363          $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
 364  
 365              if ( !this.options ) {
 366                  return;
 367              }
 368              if ( !this.options.disabled && this.visible &&
 369                      $.ui.intersect( draggable, this, this.options.tolerance, event ) ) {
 370                  dropped = this._drop.call( this, event ) || dropped;
 371              }
 372  
 373              if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ],
 374                      ( draggable.currentItem || draggable.element ) ) ) {
 375                  this.isout = true;
 376                  this.isover = false;
 377                  this._deactivate.call( this, event );
 378              }
 379  
 380          } );
 381          return dropped;
 382  
 383      },
 384      dragStart: function( draggable, event ) {
 385  
 386          // Listen for scrolling so that if the dragging causes scrolling the position of the
 387          // droppables can be recalculated (see #5003)
 388          draggable.element.parentsUntil( "body" ).on( "scroll.droppable", function() {
 389              if ( !draggable.options.refreshPositions ) {
 390                  $.ui.ddmanager.prepareOffsets( draggable, event );
 391              }
 392          } );
 393      },
 394      drag: function( draggable, event ) {
 395  
 396          // If you have a highly dynamic page, you might try this option. It renders positions
 397          // every time you move the mouse.
 398          if ( draggable.options.refreshPositions ) {
 399              $.ui.ddmanager.prepareOffsets( draggable, event );
 400          }
 401  
 402          // Run through all droppables and check their positions based on specific tolerance options
 403          $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {
 404  
 405              if ( this.options.disabled || this.greedyChild || !this.visible ) {
 406                  return;
 407              }
 408  
 409              var parentInstance, scope, parent,
 410                  intersects = $.ui.intersect( draggable, this, this.options.tolerance, event ),
 411                  c = !intersects && this.isover ?
 412                      "isout" :
 413                      ( intersects && !this.isover ? "isover" : null );
 414              if ( !c ) {
 415                  return;
 416              }
 417  
 418              if ( this.options.greedy ) {
 419  
 420                  // find droppable parents with same scope
 421                  scope = this.options.scope;
 422                  parent = this.element.parents( ":data(ui-droppable)" ).filter( function() {
 423                      return $( this ).droppable( "instance" ).options.scope === scope;
 424                  } );
 425  
 426                  if ( parent.length ) {
 427                      parentInstance = $( parent[ 0 ] ).droppable( "instance" );
 428                      parentInstance.greedyChild = ( c === "isover" );
 429                  }
 430              }
 431  
 432              // We just moved into a greedy child
 433              if ( parentInstance && c === "isover" ) {
 434                  parentInstance.isover = false;
 435                  parentInstance.isout = true;
 436                  parentInstance._out.call( parentInstance, event );
 437              }
 438  
 439              this[ c ] = true;
 440              this[ c === "isout" ? "isover" : "isout" ] = false;
 441              this[ c === "isover" ? "_over" : "_out" ].call( this, event );
 442  
 443              // We just moved out of a greedy child
 444              if ( parentInstance && c === "isout" ) {
 445                  parentInstance.isout = false;
 446                  parentInstance.isover = true;
 447                  parentInstance._over.call( parentInstance, event );
 448              }
 449          } );
 450  
 451      },
 452      dragStop: function( draggable, event ) {
 453          draggable.element.parentsUntil( "body" ).off( "scroll.droppable" );
 454  
 455          // Call prepareOffsets one final time since IE does not fire return scroll events when
 456          // overflow was caused by drag (see #5003)
 457          if ( !draggable.options.refreshPositions ) {
 458              $.ui.ddmanager.prepareOffsets( draggable, event );
 459          }
 460      }
 461  };
 462  
 463  // DEPRECATED
 464  // TODO: switch return back to widget declaration at top of file when this is removed
 465  if ( $.uiBackCompat !== false ) {
 466  
 467      // Backcompat for activeClass and hoverClass options
 468      $.widget( "ui.droppable", $.ui.droppable, {
 469          options: {
 470              hoverClass: false,
 471              activeClass: false
 472          },
 473          _addActiveClass: function() {
 474              this._super();
 475              if ( this.options.activeClass ) {
 476                  this.element.addClass( this.options.activeClass );
 477              }
 478          },
 479          _removeActiveClass: function() {
 480              this._super();
 481              if ( this.options.activeClass ) {
 482                  this.element.removeClass( this.options.activeClass );
 483              }
 484          },
 485          _addHoverClass: function() {
 486              this._super();
 487              if ( this.options.hoverClass ) {
 488                  this.element.addClass( this.options.hoverClass );
 489              }
 490          },
 491          _removeHoverClass: function() {
 492              this._super();
 493              if ( this.options.hoverClass ) {
 494                  this.element.removeClass( this.options.hoverClass );
 495              }
 496          }
 497      } );
 498  }
 499  
 500  return $.ui.droppable;
 501  
 502  } );


Generated : Tue Apr 23 08:20:01 2024 Cross-referenced by PHPXref