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


Generated : Tue Dec 17 08:20:01 2024 Cross-referenced by PHPXref