[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/2in3/2.9.0/build/yui2-dragdrop/ -> yui2-dragdrop.js (source)

   1  YUI.add('yui2-dragdrop', function(Y) {
   2      var YAHOO    = Y.YUI2;
   3      /*
   4  Copyright (c) 2011, Yahoo! Inc. All rights reserved.
   5  Code licensed under the BSD License:
   6  http://developer.yahoo.com/yui/license.html
   7  version: 2.9.0
   8  */
   9  /**
  10   * The drag and drop utility provides a framework for building drag and drop
  11   * applications.  In addition to enabling drag and drop for specific elements,
  12   * the drag and drop elements are tracked by the manager class, and the
  13   * interactions between the various elements are tracked during the drag and
  14   * the implementing code is notified about these important moments.
  15   * @module dragdrop
  16   * @title Drag and Drop
  17   * @requires yahoo,dom,event
  18   * @namespace YAHOO.util
  19   */
  20  
  21  // Only load the library once.  Rewriting the manager class would orphan 
  22  // existing drag and drop instances.
  23  if (!YAHOO.util.DragDropMgr) {
  24  
  25  /**
  26   * DragDropMgr is a singleton that tracks the element interaction for 
  27   * all DragDrop items in the window.  Generally, you will not call 
  28   * this class directly, but it does have helper methods that could 
  29   * be useful in your DragDrop implementations.
  30   * @class DragDropMgr
  31   * @static
  32   */
  33  YAHOO.util.DragDropMgr = function() {
  34  
  35      var Event = YAHOO.util.Event,
  36          Dom = YAHOO.util.Dom;
  37  
  38      return {
  39          /**
  40          * This property is used to turn on global use of the shim element on all DragDrop instances, defaults to false for backcompat. (Use: YAHOO.util.DDM.useShim = true)
  41          * @property useShim
  42          * @type Boolean
  43          * @static
  44          */
  45          useShim: false,
  46          /**
  47          * This property is used to determine if the shim is active over the screen, default false.
  48          * @private
  49          * @property _shimActive
  50          * @type Boolean
  51          * @static
  52          */
  53          _shimActive: false,
  54          /**
  55          * This property is used when useShim is set on a DragDrop object to store the current state of DDM.useShim so it can be reset when a drag operation is done.
  56          * @private
  57          * @property _shimState
  58          * @type Boolean
  59          * @static
  60          */
  61          _shimState: false,
  62          /**
  63          * This property is used when useShim is set to true, it will set the opacity on the shim to .5 for debugging. Use: (YAHOO.util.DDM._debugShim = true;)
  64          * @private
  65          * @property _debugShim
  66          * @type Boolean
  67          * @static
  68          */
  69          _debugShim: false,
  70          /**
  71          * This method will create a shim element (giving it the id of yui-ddm-shim), it also attaches the mousemove and mouseup listeners to it and attaches a scroll listener on the window
  72          * @private
  73          * @method _sizeShim
  74          * @static
  75          */
  76          _createShim: function() {
  77              var s = document.createElement('div');
  78              s.id = 'yui-ddm-shim';
  79              if (document.body.firstChild) {
  80                  document.body.insertBefore(s, document.body.firstChild);
  81              } else {
  82                  document.body.appendChild(s);
  83              }
  84              s.style.display = 'none';
  85              s.style.backgroundColor = 'red';
  86              s.style.position = 'absolute';
  87              s.style.zIndex = '99999';
  88              Dom.setStyle(s, 'opacity', '0');
  89              this._shim = s;
  90              Event.on(s, "mouseup",   this.handleMouseUp, this, true);
  91              Event.on(s, "mousemove", this.handleMouseMove, this, true);
  92              Event.on(window, 'scroll', this._sizeShim, this, true);
  93          },
  94          /**
  95          * This method will size the shim, called from activate and on window scroll event
  96          * @private
  97          * @method _sizeShim
  98          * @static
  99          */
 100          _sizeShim: function() {
 101              if (this._shimActive) {
 102                  var s = this._shim;
 103                  s.style.height = Dom.getDocumentHeight() + 'px';
 104                  s.style.width = Dom.getDocumentWidth() + 'px';
 105                  s.style.top = '0';
 106                  s.style.left = '0';
 107              }
 108          },
 109          /**
 110          * This method will create the shim element if needed, then show the shim element, size the element and set the _shimActive property to true
 111          * @private
 112          * @method _activateShim
 113          * @static
 114          */
 115          _activateShim: function() {
 116              if (this.useShim) {
 117                  if (!this._shim) {
 118                      this._createShim();
 119                  }
 120                  this._shimActive = true;
 121                  var s = this._shim,
 122                      o = '0';
 123                  if (this._debugShim) {
 124                      o = '.5';
 125                  }
 126                  Dom.setStyle(s, 'opacity', o);
 127                  this._sizeShim();
 128                  s.style.display = 'block';
 129              }
 130          },
 131          /**
 132          * This method will hide the shim element and set the _shimActive property to false
 133          * @private
 134          * @method _deactivateShim
 135          * @static
 136          */
 137          _deactivateShim: function() {
 138              this._shim.style.display = 'none';
 139              this._shimActive = false;
 140          },
 141          /**
 142          * The HTML element created to use as a shim over the document to track mouse movements
 143          * @private
 144          * @property _shim
 145          * @type HTMLElement
 146          * @static
 147          */
 148          _shim: null,
 149          /**
 150           * Two dimensional Array of registered DragDrop objects.  The first 
 151           * dimension is the DragDrop item group, the second the DragDrop 
 152           * object.
 153           * @property ids
 154           * @type {string: string}
 155           * @private
 156           * @static
 157           */
 158          ids: {},
 159  
 160          /**
 161           * Array of element ids defined as drag handles.  Used to determine 
 162           * if the element that generated the mousedown event is actually the 
 163           * handle and not the html element itself.
 164           * @property handleIds
 165           * @type {string: string}
 166           * @private
 167           * @static
 168           */
 169          handleIds: {},
 170  
 171          /**
 172           * the DragDrop object that is currently being dragged
 173           * @property dragCurrent
 174           * @type DragDrop
 175           * @private
 176           * @static
 177           **/
 178          dragCurrent: null,
 179  
 180          /**
 181           * the DragDrop object(s) that are being hovered over
 182           * @property dragOvers
 183           * @type Array
 184           * @private
 185           * @static
 186           */
 187          dragOvers: {},
 188  
 189          /**
 190           * the X distance between the cursor and the object being dragged
 191           * @property deltaX
 192           * @type int
 193           * @private
 194           * @static
 195           */
 196          deltaX: 0,
 197  
 198          /**
 199           * the Y distance between the cursor and the object being dragged
 200           * @property deltaY
 201           * @type int
 202           * @private
 203           * @static
 204           */
 205          deltaY: 0,
 206  
 207          /**
 208           * Flag to determine if we should prevent the default behavior of the
 209           * events we define. By default this is true, but this can be set to 
 210           * false if you need the default behavior (not recommended)
 211           * @property preventDefault
 212           * @type boolean
 213           * @static
 214           */
 215          preventDefault: true,
 216  
 217          /**
 218           * Flag to determine if we should stop the propagation of the events 
 219           * we generate. This is true by default but you may want to set it to
 220           * false if the html element contains other features that require the
 221           * mouse click.
 222           * @property stopPropagation
 223           * @type boolean
 224           * @static
 225           */
 226          stopPropagation: true,
 227  
 228          /**
 229           * Internal flag that is set to true when drag and drop has been
 230           * initialized
 231           * @property initialized
 232           * @private
 233           * @static
 234           */
 235          initialized: false,
 236  
 237          /**
 238           * All drag and drop can be disabled.
 239           * @property locked
 240           * @private
 241           * @static
 242           */
 243          locked: false,
 244  
 245          /**
 246           * Provides additional information about the the current set of
 247           * interactions.  Can be accessed from the event handlers. It
 248           * contains the following properties:
 249           *
 250           *       out:       onDragOut interactions
 251           *       enter:     onDragEnter interactions
 252           *       over:      onDragOver interactions
 253           *       drop:      onDragDrop interactions
 254           *       point:     The location of the cursor
 255           *       draggedRegion: The location of dragged element at the time
 256           *                      of the interaction
 257           *       sourceRegion: The location of the source elemtn at the time
 258           *                     of the interaction
 259           *       validDrop: boolean
 260           * @property interactionInfo
 261           * @type object
 262           * @static
 263           */
 264          interactionInfo: null,
 265  
 266          /**
 267           * Called the first time an element is registered.
 268           * @method init
 269           * @private
 270           * @static
 271           */
 272          init: function() {
 273              this.initialized = true;
 274          },
 275  
 276          /**
 277           * In point mode, drag and drop interaction is defined by the 
 278           * location of the cursor during the drag/drop
 279           * @property POINT
 280           * @type int
 281           * @static
 282           * @final
 283           */
 284          POINT: 0,
 285  
 286          /**
 287           * In intersect mode, drag and drop interaction is defined by the 
 288           * cursor position or the amount of overlap of two or more drag and 
 289           * drop objects.
 290           * @property INTERSECT
 291           * @type int
 292           * @static
 293           * @final
 294           */
 295          INTERSECT: 1,
 296  
 297          /**
 298           * In intersect mode, drag and drop interaction is defined only by the 
 299           * overlap of two or more drag and drop objects.
 300           * @property STRICT_INTERSECT
 301           * @type int
 302           * @static
 303           * @final
 304           */
 305          STRICT_INTERSECT: 2,
 306  
 307          /**
 308           * The current drag and drop mode.  Default: POINT
 309           * @property mode
 310           * @type int
 311           * @static
 312           */
 313          mode: 0,
 314  
 315          /**
 316           * Runs method on all drag and drop objects
 317           * @method _execOnAll
 318           * @private
 319           * @static
 320           */
 321          _execOnAll: function(sMethod, args) {
 322              for (var i in this.ids) {
 323                  for (var j in this.ids[i]) {
 324                      var oDD = this.ids[i][j];
 325                      if (! this.isTypeOfDD(oDD)) {
 326                          continue;
 327                      }
 328                      oDD[sMethod].apply(oDD, args);
 329                  }
 330              }
 331          },
 332  
 333          /**
 334           * Drag and drop initialization.  Sets up the global event handlers
 335           * @method _onLoad
 336           * @private
 337           * @static
 338           */
 339          _onLoad: function() {
 340  
 341              this.init();
 342  
 343              Event.on(document, "mouseup",   this.handleMouseUp, this, true);
 344              Event.on(document, "mousemove", this.handleMouseMove, this, true);
 345              Event.on(window,   "unload",    this._onUnload, this, true);
 346              Event.on(window,   "resize",    this._onResize, this, true);
 347              // Event.on(window,   "mouseout",    this._test);
 348  
 349          },
 350  
 351          /**
 352           * Reset constraints on all drag and drop objs
 353           * @method _onResize
 354           * @private
 355           * @static
 356           */
 357          _onResize: function(e) {
 358              this._execOnAll("resetConstraints", []);
 359          },
 360  
 361          /**
 362           * Lock all drag and drop functionality
 363           * @method lock
 364           * @static
 365           */
 366          lock: function() { this.locked = true; },
 367  
 368          /**
 369           * Unlock all drag and drop functionality
 370           * @method unlock
 371           * @static
 372           */
 373          unlock: function() { this.locked = false; },
 374  
 375          /**
 376           * Is drag and drop locked?
 377           * @method isLocked
 378           * @return {boolean} True if drag and drop is locked, false otherwise.
 379           * @static
 380           */
 381          isLocked: function() { return this.locked; },
 382  
 383          /**
 384           * Location cache that is set for all drag drop objects when a drag is
 385           * initiated, cleared when the drag is finished.
 386           * @property locationCache
 387           * @private
 388           * @static
 389           */
 390          locationCache: {},
 391  
 392          /**
 393           * Set useCache to false if you want to force object the lookup of each
 394           * drag and drop linked element constantly during a drag.
 395           * @property useCache
 396           * @type boolean
 397           * @static
 398           */
 399          useCache: true,
 400  
 401          /**
 402           * The number of pixels that the mouse needs to move after the 
 403           * mousedown before the drag is initiated.  Default=3;
 404           * @property clickPixelThresh
 405           * @type int
 406           * @static
 407           */
 408          clickPixelThresh: 3,
 409  
 410          /**
 411           * The number of milliseconds after the mousedown event to initiate the
 412           * drag if we don't get a mouseup event. Default=1000
 413           * @property clickTimeThresh
 414           * @type int
 415           * @static
 416           */
 417          clickTimeThresh: 1000,
 418  
 419          /**
 420           * Flag that indicates that either the drag pixel threshold or the 
 421           * mousdown time threshold has been met
 422           * @property dragThreshMet
 423           * @type boolean
 424           * @private
 425           * @static
 426           */
 427          dragThreshMet: false,
 428  
 429          /**
 430           * Timeout used for the click time threshold
 431           * @property clickTimeout
 432           * @type Object
 433           * @private
 434           * @static
 435           */
 436          clickTimeout: null,
 437  
 438          /**
 439           * The X position of the mousedown event stored for later use when a 
 440           * drag threshold is met.
 441           * @property startX
 442           * @type int
 443           * @private
 444           * @static
 445           */
 446          startX: 0,
 447  
 448          /**
 449           * The Y position of the mousedown event stored for later use when a 
 450           * drag threshold is met.
 451           * @property startY
 452           * @type int
 453           * @private
 454           * @static
 455           */
 456          startY: 0,
 457  
 458          /**
 459           * Flag to determine if the drag event was fired from the click timeout and
 460           * not the mouse move threshold.
 461           * @property fromTimeout
 462           * @type boolean
 463           * @private
 464           * @static
 465           */
 466          fromTimeout: false,
 467  
 468          /**
 469           * Each DragDrop instance must be registered with the DragDropMgr.  
 470           * This is executed in DragDrop.init()
 471           * @method regDragDrop
 472           * @param {DragDrop} oDD the DragDrop object to register
 473           * @param {String} sGroup the name of the group this element belongs to
 474           * @static
 475           */
 476          regDragDrop: function(oDD, sGroup) {
 477              if (!this.initialized) { this.init(); }
 478              
 479              if (!this.ids[sGroup]) {
 480                  this.ids[sGroup] = {};
 481              }
 482              this.ids[sGroup][oDD.id] = oDD;
 483          },
 484  
 485          /**
 486           * Removes the supplied dd instance from the supplied group. Executed
 487           * by DragDrop.removeFromGroup, so don't call this function directly.
 488           * @method removeDDFromGroup
 489           * @private
 490           * @static
 491           */
 492          removeDDFromGroup: function(oDD, sGroup) {
 493              if (!this.ids[sGroup]) {
 494                  this.ids[sGroup] = {};
 495              }
 496  
 497              var obj = this.ids[sGroup];
 498              if (obj && obj[oDD.id]) {
 499                  delete obj[oDD.id];
 500              }
 501          },
 502  
 503          /**
 504           * Unregisters a drag and drop item.  This is executed in 
 505           * DragDrop.unreg, use that method instead of calling this directly.
 506           * @method _remove
 507           * @private
 508           * @static
 509           */
 510          _remove: function(oDD) {
 511              for (var g in oDD.groups) {
 512                  if (g) {
 513                      var item = this.ids[g];
 514                      if (item && item[oDD.id]) {
 515                          delete item[oDD.id];
 516                      }
 517                  }
 518                  
 519              }
 520              delete this.handleIds[oDD.id];
 521          },
 522  
 523          /**
 524           * Each DragDrop handle element must be registered.  This is done
 525           * automatically when executing DragDrop.setHandleElId()
 526           * @method regHandle
 527           * @param {String} sDDId the DragDrop id this element is a handle for
 528           * @param {String} sHandleId the id of the element that is the drag 
 529           * handle
 530           * @static
 531           */
 532          regHandle: function(sDDId, sHandleId) {
 533              if (!this.handleIds[sDDId]) {
 534                  this.handleIds[sDDId] = {};
 535              }
 536              this.handleIds[sDDId][sHandleId] = sHandleId;
 537          },
 538  
 539          /**
 540           * Utility function to determine if a given element has been 
 541           * registered as a drag drop item.
 542           * @method isDragDrop
 543           * @param {String} id the element id to check
 544           * @return {boolean} true if this element is a DragDrop item, 
 545           * false otherwise
 546           * @static
 547           */
 548          isDragDrop: function(id) {
 549              return ( this.getDDById(id) ) ? true : false;
 550          },
 551  
 552          /**
 553           * Returns the drag and drop instances that are in all groups the
 554           * passed in instance belongs to.
 555           * @method getRelated
 556           * @param {DragDrop} p_oDD the obj to get related data for
 557           * @param {boolean} bTargetsOnly if true, only return targetable objs
 558           * @return {DragDrop[]} the related instances
 559           * @static
 560           */
 561          getRelated: function(p_oDD, bTargetsOnly) {
 562              var oDDs = [];
 563              for (var i in p_oDD.groups) {
 564                  for (var j in this.ids[i]) {
 565                      var dd = this.ids[i][j];
 566                      if (! this.isTypeOfDD(dd)) {
 567                          continue;
 568                      }
 569                      if (!bTargetsOnly || dd.isTarget) {
 570                          oDDs[oDDs.length] = dd;
 571                      }
 572                  }
 573              }
 574  
 575              return oDDs;
 576          },
 577  
 578          /**
 579           * Returns true if the specified dd target is a legal target for 
 580           * the specifice drag obj
 581           * @method isLegalTarget
 582           * @param {DragDrop} the drag obj
 583           * @param {DragDrop} the target
 584           * @return {boolean} true if the target is a legal target for the 
 585           * dd obj
 586           * @static
 587           */
 588          isLegalTarget: function (oDD, oTargetDD) {
 589              var targets = this.getRelated(oDD, true);
 590              for (var i=0, len=targets.length;i<len;++i) {
 591                  if (targets[i].id == oTargetDD.id) {
 592                      return true;
 593                  }
 594              }
 595  
 596              return false;
 597          },
 598  
 599          /**
 600           * My goal is to be able to transparently determine if an object is
 601           * typeof DragDrop, and the exact subclass of DragDrop.  typeof 
 602           * returns "object", oDD.constructor.toString() always returns
 603           * "DragDrop" and not the name of the subclass.  So for now it just
 604           * evaluates a well-known variable in DragDrop.
 605           * @method isTypeOfDD
 606           * @param {Object} the object to evaluate
 607           * @return {boolean} true if typeof oDD = DragDrop
 608           * @static
 609           */
 610          isTypeOfDD: function (oDD) {
 611              return (oDD && oDD.__ygDragDrop);
 612          },
 613  
 614          /**
 615           * Utility function to determine if a given element has been 
 616           * registered as a drag drop handle for the given Drag Drop object.
 617           * @method isHandle
 618           * @param {String} id the element id to check
 619           * @return {boolean} true if this element is a DragDrop handle, false 
 620           * otherwise
 621           * @static
 622           */
 623          isHandle: function(sDDId, sHandleId) {
 624              return ( this.handleIds[sDDId] && 
 625                              this.handleIds[sDDId][sHandleId] );
 626          },
 627  
 628          /**
 629           * Returns the DragDrop instance for a given id
 630           * @method getDDById
 631           * @param {String} id the id of the DragDrop object
 632           * @return {DragDrop} the drag drop object, null if it is not found
 633           * @static
 634           */
 635          getDDById: function(id) {
 636              for (var i in this.ids) {
 637                  if (this.ids[i][id]) {
 638                      return this.ids[i][id];
 639                  }
 640              }
 641              return null;
 642          },
 643  
 644          /**
 645           * Fired after a registered DragDrop object gets the mousedown event.
 646           * Sets up the events required to track the object being dragged
 647           * @method handleMouseDown
 648           * @param {Event} e the event
 649           * @param oDD the DragDrop object being dragged
 650           * @private
 651           * @static
 652           */
 653          handleMouseDown: function(e, oDD) {
 654              //this._activateShim();
 655  
 656              this.currentTarget = YAHOO.util.Event.getTarget(e);
 657  
 658              this.dragCurrent = oDD;
 659  
 660              var el = oDD.getEl();
 661  
 662              // track start position
 663              this.startX = YAHOO.util.Event.getPageX(e);
 664              this.startY = YAHOO.util.Event.getPageY(e);
 665  
 666              this.deltaX = this.startX - el.offsetLeft;
 667              this.deltaY = this.startY - el.offsetTop;
 668  
 669              this.dragThreshMet = false;
 670  
 671              this.clickTimeout = setTimeout( 
 672                      function() { 
 673                          var DDM = YAHOO.util.DDM;
 674                          DDM.startDrag(DDM.startX, DDM.startY);
 675                          DDM.fromTimeout = true;
 676                      }, 
 677                      this.clickTimeThresh );
 678          },
 679  
 680          /**
 681           * Fired when either the drag pixel threshold or the mousedown hold 
 682           * time threshold has been met.
 683           * @method startDrag
 684           * @param x {int} the X position of the original mousedown
 685           * @param y {int} the Y position of the original mousedown
 686           * @static
 687           */
 688          startDrag: function(x, y) {
 689              if (this.dragCurrent && this.dragCurrent.useShim) {
 690                  this._shimState = this.useShim;
 691                  this.useShim = true;
 692              }
 693              this._activateShim();
 694              clearTimeout(this.clickTimeout);
 695              var dc = this.dragCurrent;
 696              if (dc && dc.events.b4StartDrag) {
 697                  dc.b4StartDrag(x, y);
 698                  dc.fireEvent('b4StartDragEvent', { x: x, y: y });
 699              }
 700              if (dc && dc.events.startDrag) {
 701                  dc.startDrag(x, y);
 702                  dc.fireEvent('startDragEvent', { x: x, y: y });
 703              }
 704              this.dragThreshMet = true;
 705          },
 706  
 707          /**
 708           * Internal function to handle the mouseup event.  Will be invoked 
 709           * from the context of the document.
 710           * @method handleMouseUp
 711           * @param {Event} e the event
 712           * @private
 713           * @static
 714           */
 715          handleMouseUp: function(e) {
 716              if (this.dragCurrent) {
 717                  clearTimeout(this.clickTimeout);
 718  
 719                  if (this.dragThreshMet) {
 720                      if (this.fromTimeout) {
 721                          this.fromTimeout = false;
 722                          this.handleMouseMove(e);
 723                      }
 724                      this.fromTimeout = false;
 725                      this.fireEvents(e, true);
 726                  } else {
 727                  }
 728  
 729                  this.stopDrag(e);
 730  
 731                  this.stopEvent(e);
 732              }
 733          },
 734  
 735          /**
 736           * Utility to stop event propagation and event default, if these 
 737           * features are turned on.
 738           * @method stopEvent
 739           * @param {Event} e the event as returned by this.getEvent()
 740           * @static
 741           */
 742          stopEvent: function(e) {
 743              if (this.stopPropagation) {
 744                  YAHOO.util.Event.stopPropagation(e);
 745              }
 746  
 747              if (this.preventDefault) {
 748                  YAHOO.util.Event.preventDefault(e);
 749              }
 750          },
 751  
 752          /** 
 753           * Ends the current drag, cleans up the state, and fires the endDrag
 754           * and mouseUp events.  Called internally when a mouseup is detected
 755           * during the drag.  Can be fired manually during the drag by passing
 756           * either another event (such as the mousemove event received in onDrag)
 757           * or a fake event with pageX and pageY defined (so that endDrag and
 758           * onMouseUp have usable position data.).  Alternatively, pass true
 759           * for the silent parameter so that the endDrag and onMouseUp events
 760           * are skipped (so no event data is needed.)
 761           *
 762           * @method stopDrag
 763           * @param {Event} e the mouseup event, another event (or a fake event) 
 764           *                  with pageX and pageY defined, or nothing if the 
 765           *                  silent parameter is true
 766           * @param {boolean} silent skips the enddrag and mouseup events if true
 767           * @static
 768           */
 769          stopDrag: function(e, silent) {
 770              var dc = this.dragCurrent;
 771              // Fire the drag end event for the item that was dragged
 772              if (dc && !silent) {
 773                  if (this.dragThreshMet) {
 774                      if (dc.events.b4EndDrag) {
 775                          dc.b4EndDrag(e);
 776                          dc.fireEvent('b4EndDragEvent', { e: e });
 777                      }
 778                      if (dc.events.endDrag) {
 779                          dc.endDrag(e);
 780                          dc.fireEvent('endDragEvent', { e: e });
 781                      }
 782                  }
 783                  if (dc.events.mouseUp) {
 784                      dc.onMouseUp(e);
 785                      dc.fireEvent('mouseUpEvent', { e: e });
 786                  }
 787              }
 788  
 789              if (this._shimActive) {
 790                  this._deactivateShim();
 791                  if (this.dragCurrent && this.dragCurrent.useShim) {
 792                      this.useShim = this._shimState;
 793                      this._shimState = false;
 794                  }
 795              }
 796  
 797              this.dragCurrent = null;
 798              this.dragOvers = {};
 799          },
 800  
 801          /** 
 802           * Internal function to handle the mousemove event.  Will be invoked 
 803           * from the context of the html element.
 804           *
 805           * @TODO figure out what we can do about mouse events lost when the 
 806           * user drags objects beyond the window boundary.  Currently we can 
 807           * detect this in internet explorer by verifying that the mouse is 
 808           * down during the mousemove event.  Firefox doesn't give us the 
 809           * button state on the mousemove event.
 810           * @method handleMouseMove
 811           * @param {Event} e the event
 812           * @private
 813           * @static
 814           */
 815          handleMouseMove: function(e) {
 816  
 817              var dc = this.dragCurrent;
 818              if (dc) {
 819  
 820                  // var button = e.which || e.button;
 821  
 822                  // check for IE < 9 mouseup outside of page boundary
 823                  if (YAHOO.env.ua.ie && (YAHOO.env.ua.ie < 9) && !e.button) {
 824                      this.stopEvent(e);
 825                      return this.handleMouseUp(e);
 826                  } else {
 827                      if (e.clientX < 0 || e.clientY < 0) {
 828                          //This will stop the element from leaving the viewport in FF, Opera & Safari
 829                          //Not turned on yet
 830                          //this.stopEvent(e);
 831                          //return false;
 832                      }
 833                  }
 834  
 835                  if (!this.dragThreshMet) {
 836                      var diffX = Math.abs(this.startX - YAHOO.util.Event.getPageX(e));
 837                      var diffY = Math.abs(this.startY - YAHOO.util.Event.getPageY(e));
 838                      if (diffX > this.clickPixelThresh || 
 839                                  diffY > this.clickPixelThresh) {
 840                          this.startDrag(this.startX, this.startY);
 841                      }
 842                  }
 843  
 844                  if (this.dragThreshMet) {
 845                      if (dc && dc.events.b4Drag) {
 846                          dc.b4Drag(e);
 847                          dc.fireEvent('b4DragEvent', { e: e});
 848                      }
 849                      if (dc && dc.events.drag) {
 850                          dc.onDrag(e);
 851                          dc.fireEvent('dragEvent', { e: e});
 852                      }
 853                      if (dc) {
 854                          this.fireEvents(e, false);
 855                      }
 856                  }
 857  
 858                  this.stopEvent(e);
 859              }
 860          },
 861          
 862          /**
 863           * Iterates over all of the DragDrop elements to find ones we are 
 864           * hovering over or dropping on
 865           * @method fireEvents
 866           * @param {Event} e the event
 867           * @param {boolean} isDrop is this a drop op or a mouseover op?
 868           * @private
 869           * @static
 870           */
 871          fireEvents: function(e, isDrop) {
 872              var dc = this.dragCurrent;
 873  
 874              // If the user did the mouse up outside of the window, we could 
 875              // get here even though we have ended the drag.
 876              // If the config option dragOnly is true, bail out and don't fire the events
 877              if (!dc || dc.isLocked() || dc.dragOnly) {
 878                  return;
 879              }
 880  
 881              var x = YAHOO.util.Event.getPageX(e),
 882                  y = YAHOO.util.Event.getPageY(e),
 883                  pt = new YAHOO.util.Point(x,y),
 884                  pos = dc.getTargetCoord(pt.x, pt.y),
 885                  el = dc.getDragEl(),
 886                  events = ['out', 'over', 'drop', 'enter'],
 887                  curRegion = new YAHOO.util.Region( pos.y, 
 888                                                 pos.x + el.offsetWidth,
 889                                                 pos.y + el.offsetHeight, 
 890                                                 pos.x ),
 891              
 892                  oldOvers = [], // cache the previous dragOver array
 893                  inGroupsObj  = {},
 894                  b4Results = {},
 895                  inGroups  = [],
 896                  data = {
 897                      outEvts: [],
 898                      overEvts: [],
 899                      dropEvts: [],
 900                      enterEvts: []
 901                  };
 902  
 903  
 904              // Check to see if the object(s) we were hovering over is no longer 
 905              // being hovered over so we can fire the onDragOut event
 906              for (var i in this.dragOvers) {
 907  
 908                  var ddo = this.dragOvers[i];
 909  
 910                  if (! this.isTypeOfDD(ddo)) {
 911                      continue;
 912                  }
 913                  if (! this.isOverTarget(pt, ddo, this.mode, curRegion)) {
 914                      data.outEvts.push( ddo );
 915                  }
 916  
 917                  oldOvers[i] = true;
 918                  delete this.dragOvers[i];
 919              }
 920  
 921              for (var sGroup in dc.groups) {
 922                  
 923                  if ("string" != typeof sGroup) {
 924                      continue;
 925                  }
 926  
 927                  for (i in this.ids[sGroup]) {
 928                      var oDD = this.ids[sGroup][i];
 929                      if (! this.isTypeOfDD(oDD)) {
 930                          continue;
 931                      }
 932  
 933                      if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
 934                          if (this.isOverTarget(pt, oDD, this.mode, curRegion)) {
 935                              inGroupsObj[sGroup] = true;
 936                              // look for drop interactions
 937                              if (isDrop) {
 938                                  data.dropEvts.push( oDD );
 939                              // look for drag enter and drag over interactions
 940                              } else {
 941  
 942                                  // initial drag over: dragEnter fires
 943                                  if (!oldOvers[oDD.id]) {
 944                                      data.enterEvts.push( oDD );
 945                                  // subsequent drag overs: dragOver fires
 946                                  } else {
 947                                      data.overEvts.push( oDD );
 948                                  }
 949  
 950                                  this.dragOvers[oDD.id] = oDD;
 951                              }
 952                          }
 953                      }
 954                  }
 955              }
 956  
 957              this.interactionInfo = {
 958                  out:       data.outEvts,
 959                  enter:     data.enterEvts,
 960                  over:      data.overEvts,
 961                  drop:      data.dropEvts,
 962                  point:     pt,
 963                  draggedRegion:    curRegion,
 964                  sourceRegion: this.locationCache[dc.id],
 965                  validDrop: isDrop
 966              };
 967  
 968              
 969              for (var inG in inGroupsObj) {
 970                  inGroups.push(inG);
 971              }
 972  
 973              // notify about a drop that did not find a target
 974              if (isDrop && !data.dropEvts.length) {
 975                  this.interactionInfo.validDrop = false;
 976                  if (dc.events.invalidDrop) {
 977                      dc.onInvalidDrop(e);
 978                      dc.fireEvent('invalidDropEvent', { e: e });
 979                  }
 980              }
 981              for (i = 0; i < events.length; i++) {
 982                  var tmp = null;
 983                  if (data[events[i] + 'Evts']) {
 984                      tmp = data[events[i] + 'Evts'];
 985                  }
 986                  if (tmp && tmp.length) {
 987                      var type = events[i].charAt(0).toUpperCase() + events[i].substr(1),
 988                          ev = 'onDrag' + type,
 989                          b4 = 'b4Drag' + type,
 990                          cev = 'drag' + type + 'Event',
 991                          check = 'drag' + type;
 992                      if (this.mode) {
 993                          if (dc.events[b4]) {
 994                              dc[b4](e, tmp, inGroups);
 995                              b4Results[ev] = dc.fireEvent(b4 + 'Event', { event: e, info: tmp, group: inGroups });
 996                              
 997                          }
 998                          if (dc.events[check] && (b4Results[ev] !== false)) {
 999                              dc[ev](e, tmp, inGroups);
1000                              dc.fireEvent(cev, { event: e, info: tmp, group: inGroups });
1001                          }
1002                      } else {
1003                          for (var b = 0, len = tmp.length; b < len; ++b) {
1004                              if (dc.events[b4]) {
1005                                  dc[b4](e, tmp[b].id, inGroups[0]);
1006                                  b4Results[ev] = dc.fireEvent(b4 + 'Event', { event: e, info: tmp[b].id, group: inGroups[0] });
1007                              }
1008                              if (dc.events[check] && (b4Results[ev] !== false)) {
1009                                  dc[ev](e, tmp[b].id, inGroups[0]);
1010                                  dc.fireEvent(cev, { event: e, info: tmp[b].id, group: inGroups[0] });
1011                              }
1012                          }
1013                      }
1014                  }
1015              }
1016          },
1017  
1018          /**
1019           * Helper function for getting the best match from the list of drag 
1020           * and drop objects returned by the drag and drop events when we are 
1021           * in INTERSECT mode.  It returns either the first object that the 
1022           * cursor is over, or the object that has the greatest overlap with 
1023           * the dragged element.
1024           * @method getBestMatch
1025           * @param  {DragDrop[]} dds The array of drag and drop objects 
1026           * targeted
1027           * @return {DragDrop}       The best single match
1028           * @static
1029           */
1030          getBestMatch: function(dds) {
1031              var winner = null;
1032  
1033              var len = dds.length;
1034  
1035              if (len == 1) {
1036                  winner = dds[0];
1037              } else {
1038                  // Loop through the targeted items
1039                  for (var i=0; i<len; ++i) {
1040                      var dd = dds[i];
1041                      // If the cursor is over the object, it wins.  If the 
1042                      // cursor is over multiple matches, the first one we come
1043                      // to wins.
1044                      if (this.mode == this.INTERSECT && dd.cursorIsOver) {
1045                          winner = dd;
1046                          break;
1047                      // Otherwise the object with the most overlap wins
1048                      } else {
1049                          if (!winner || !winner.overlap || (dd.overlap &&
1050                              winner.overlap.getArea() < dd.overlap.getArea())) {
1051                              winner = dd;
1052                          }
1053                      }
1054                  }
1055              }
1056  
1057              return winner;
1058          },
1059  
1060          /**
1061           * Refreshes the cache of the top-left and bottom-right points of the 
1062           * drag and drop objects in the specified group(s).  This is in the
1063           * format that is stored in the drag and drop instance, so typical 
1064           * usage is:
1065           * <code>
1066           * YAHOO.util.DragDropMgr.refreshCache(ddinstance.groups);
1067           * </code>
1068           * Alternatively:
1069           * <code>
1070           * YAHOO.util.DragDropMgr.refreshCache({group1:true, group2:true});
1071           * </code>
1072           * @TODO this really should be an indexed array.  Alternatively this
1073           * method could accept both.
1074           * @method refreshCache
1075           * @param {Object} groups an associative array of groups to refresh
1076           * @static
1077           */
1078          refreshCache: function(groups) {
1079  
1080              // refresh everything if group array is not provided
1081              var g = groups || this.ids;
1082  
1083              for (var sGroup in g) {
1084                  if ("string" != typeof sGroup) {
1085                      continue;
1086                  }
1087                  for (var i in this.ids[sGroup]) {
1088                      var oDD = this.ids[sGroup][i];
1089  
1090                      if (this.isTypeOfDD(oDD)) {
1091                          var loc = this.getLocation(oDD);
1092                          if (loc) {
1093                              this.locationCache[oDD.id] = loc;
1094                          } else {
1095                              delete this.locationCache[oDD.id];
1096                          }
1097                      }
1098                  }
1099              }
1100          },
1101  
1102          /**
1103           * This checks to make sure an element exists and is in the DOM.  The
1104           * main purpose is to handle cases where innerHTML is used to remove
1105           * drag and drop objects from the DOM.  IE provides an 'unspecified
1106           * error' when trying to access the offsetParent of such an element
1107           * @method verifyEl
1108           * @param {HTMLElement} el the element to check
1109           * @return {boolean} true if the element looks usable
1110           * @static
1111           */
1112          verifyEl: function(el) {
1113              try {
1114                  if (el) {
1115                      var parent = el.offsetParent;
1116                      if (parent) {
1117                          return true;
1118                      }
1119                  }
1120              } catch(e) {
1121              }
1122  
1123              return false;
1124          },
1125          
1126          /**
1127           * Returns a Region object containing the drag and drop element's position
1128           * and size, including the padding configured for it
1129           * @method getLocation
1130           * @param {DragDrop} oDD the drag and drop object to get the 
1131           *                       location for
1132           * @return {YAHOO.util.Region} a Region object representing the total area
1133           *                             the element occupies, including any padding
1134           *                             the instance is configured for.
1135           * @static
1136           */
1137          getLocation: function(oDD) {
1138              if (! this.isTypeOfDD(oDD)) {
1139                  return null;
1140              }
1141  
1142              var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
1143  
1144              try {
1145                  pos= YAHOO.util.Dom.getXY(el);
1146              } catch (e) { }
1147  
1148              if (!pos) {
1149                  return null;
1150              }
1151  
1152              x1 = pos[0];
1153              x2 = x1 + el.offsetWidth;
1154              y1 = pos[1];
1155              y2 = y1 + el.offsetHeight;
1156  
1157              t = y1 - oDD.padding[0];
1158              r = x2 + oDD.padding[1];
1159              b = y2 + oDD.padding[2];
1160              l = x1 - oDD.padding[3];
1161  
1162              return new YAHOO.util.Region( t, r, b, l );
1163          },
1164  
1165          /**
1166           * Checks the cursor location to see if it over the target
1167           * @method isOverTarget
1168           * @param {YAHOO.util.Point} pt The point to evaluate
1169           * @param {DragDrop} oTarget the DragDrop object we are inspecting
1170           * @param {boolean} intersect true if we are in intersect mode
1171           * @param {YAHOO.util.Region} pre-cached location of the dragged element
1172           * @return {boolean} true if the mouse is over the target
1173           * @private
1174           * @static
1175           */
1176          isOverTarget: function(pt, oTarget, intersect, curRegion) {
1177              // use cache if available
1178              var loc = this.locationCache[oTarget.id];
1179              if (!loc || !this.useCache) {
1180                  loc = this.getLocation(oTarget);
1181                  this.locationCache[oTarget.id] = loc;
1182  
1183              }
1184  
1185              if (!loc) {
1186                  return false;
1187              }
1188  
1189              oTarget.cursorIsOver = loc.contains( pt );
1190  
1191              // DragDrop is using this as a sanity check for the initial mousedown
1192              // in this case we are done.  In POINT mode, if the drag obj has no
1193              // contraints, we are done. Otherwise we need to evaluate the 
1194              // region the target as occupies to determine if the dragged element
1195              // overlaps with it.
1196              
1197              var dc = this.dragCurrent;
1198              if (!dc || (!intersect && !dc.constrainX && !dc.constrainY)) {
1199  
1200                  //if (oTarget.cursorIsOver) {
1201                  //}
1202                  return oTarget.cursorIsOver;
1203              }
1204  
1205              oTarget.overlap = null;
1206  
1207  
1208              // Get the current location of the drag element, this is the
1209              // location of the mouse event less the delta that represents
1210              // where the original mousedown happened on the element.  We
1211              // need to consider constraints and ticks as well.
1212  
1213              if (!curRegion) {
1214                  var pos = dc.getTargetCoord(pt.x, pt.y);
1215                  var el = dc.getDragEl();
1216                  curRegion = new YAHOO.util.Region( pos.y, 
1217                                                     pos.x + el.offsetWidth,
1218                                                     pos.y + el.offsetHeight, 
1219                                                     pos.x );
1220              }
1221  
1222              var overlap = curRegion.intersect(loc);
1223  
1224              if (overlap) {
1225                  oTarget.overlap = overlap;
1226                  return (intersect) ? true : oTarget.cursorIsOver;
1227              } else {
1228                  return false;
1229              }
1230          },
1231  
1232          /**
1233           * unload event handler
1234           * @method _onUnload
1235           * @private
1236           * @static
1237           */
1238          _onUnload: function(e, me) {
1239              this.unregAll();
1240          },
1241  
1242          /**
1243           * Cleans up the drag and drop events and objects.
1244           * @method unregAll
1245           * @private
1246           * @static
1247           */
1248          unregAll: function() {
1249  
1250              if (this.dragCurrent) {
1251                  this.stopDrag();
1252                  this.dragCurrent = null;
1253              }
1254  
1255              this._execOnAll("unreg", []);
1256  
1257              //for (var i in this.elementCache) {
1258                  //delete this.elementCache[i];
1259              //}
1260              //this.elementCache = {};
1261  
1262              this.ids = {};
1263          },
1264  
1265          /**
1266           * A cache of DOM elements
1267           * @property elementCache
1268           * @private
1269           * @static
1270           * @deprecated elements are not cached now
1271           */
1272          elementCache: {},
1273          
1274          /**
1275           * Get the wrapper for the DOM element specified
1276           * @method getElWrapper
1277           * @param {String} id the id of the element to get
1278           * @return {YAHOO.util.DDM.ElementWrapper} the wrapped element
1279           * @private
1280           * @deprecated This wrapper isn't that useful
1281           * @static
1282           */
1283          getElWrapper: function(id) {
1284              var oWrapper = this.elementCache[id];
1285              if (!oWrapper || !oWrapper.el) {
1286                  oWrapper = this.elementCache[id] = 
1287                      new this.ElementWrapper(YAHOO.util.Dom.get(id));
1288              }
1289              return oWrapper;
1290          },
1291  
1292          /**
1293           * Returns the actual DOM element
1294           * @method getElement
1295           * @param {String} id the id of the elment to get
1296           * @return {Object} The element
1297           * @deprecated use YAHOO.util.Dom.get instead
1298           * @static
1299           */
1300          getElement: function(id) {
1301              return YAHOO.util.Dom.get(id);
1302          },
1303          
1304          /**
1305           * Returns the style property for the DOM element (i.e., 
1306           * document.getElById(id).style)
1307           * @method getCss
1308           * @param {String} id the id of the elment to get
1309           * @return {Object} The style property of the element
1310           * @deprecated use YAHOO.util.Dom instead
1311           * @static
1312           */
1313          getCss: function(id) {
1314              var el = YAHOO.util.Dom.get(id);
1315              return (el) ? el.style : null;
1316          },
1317  
1318          /**
1319           * Inner class for cached elements
1320           * @class DragDropMgr.ElementWrapper
1321           * @for DragDropMgr
1322           * @private
1323           * @deprecated
1324           */
1325          ElementWrapper: function(el) {
1326                  /**
1327                   * The element
1328                   * @property el
1329                   */
1330                  this.el = el || null;
1331                  /**
1332                   * The element id
1333                   * @property id
1334                   */
1335                  this.id = this.el && el.id;
1336                  /**
1337                   * A reference to the style property
1338                   * @property css
1339                   */
1340                  this.css = this.el && el.style;
1341              },
1342  
1343          /**
1344           * Returns the X position of an html element
1345           * @method getPosX
1346           * @param el the element for which to get the position
1347           * @return {int} the X coordinate
1348           * @for DragDropMgr
1349           * @deprecated use YAHOO.util.Dom.getX instead
1350           * @static
1351           */
1352          getPosX: function(el) {
1353              return YAHOO.util.Dom.getX(el);
1354          },
1355  
1356          /**
1357           * Returns the Y position of an html element
1358           * @method getPosY
1359           * @param el the element for which to get the position
1360           * @return {int} the Y coordinate
1361           * @deprecated use YAHOO.util.Dom.getY instead
1362           * @static
1363           */
1364          getPosY: function(el) {
1365              return YAHOO.util.Dom.getY(el); 
1366          },
1367  
1368          /**
1369           * Swap two nodes.  In IE, we use the native method, for others we 
1370           * emulate the IE behavior
1371           * @method swapNode
1372           * @param n1 the first node to swap
1373           * @param n2 the other node to swap
1374           * @static
1375           */
1376          swapNode: function(n1, n2) {
1377              if (n1.swapNode) {
1378                  n1.swapNode(n2);
1379              } else {
1380                  var p = n2.parentNode;
1381                  var s = n2.nextSibling;
1382  
1383                  if (s == n1) {
1384                      p.insertBefore(n1, n2);
1385                  } else if (n2 == n1.nextSibling) {
1386                      p.insertBefore(n2, n1);
1387                  } else {
1388                      n1.parentNode.replaceChild(n2, n1);
1389                      p.insertBefore(n1, s);
1390                  }
1391              }
1392          },
1393  
1394          /**
1395           * Returns the current scroll position
1396           * @method getScroll
1397           * @private
1398           * @static
1399           */
1400          getScroll: function () {
1401              var t, l, dde=document.documentElement, db=document.body;
1402              if (dde && (dde.scrollTop || dde.scrollLeft)) {
1403                  t = dde.scrollTop;
1404                  l = dde.scrollLeft;
1405              } else if (db) {
1406                  t = db.scrollTop;
1407                  l = db.scrollLeft;
1408              } else {
1409              }
1410              return { top: t, left: l };
1411          },
1412  
1413          /**
1414           * Returns the specified element style property
1415           * @method getStyle
1416           * @param {HTMLElement} el          the element
1417           * @param {string}      styleProp   the style property
1418           * @return {string} The value of the style property
1419           * @deprecated use YAHOO.util.Dom.getStyle
1420           * @static
1421           */
1422          getStyle: function(el, styleProp) {
1423              return YAHOO.util.Dom.getStyle(el, styleProp);
1424          },
1425  
1426          /**
1427           * Gets the scrollTop
1428           * @method getScrollTop
1429           * @return {int} the document's scrollTop
1430           * @static
1431           */
1432          getScrollTop: function () { return this.getScroll().top; },
1433  
1434          /**
1435           * Gets the scrollLeft
1436           * @method getScrollLeft
1437           * @return {int} the document's scrollTop
1438           * @static
1439           */
1440          getScrollLeft: function () { return this.getScroll().left; },
1441  
1442          /**
1443           * Sets the x/y position of an element to the location of the
1444           * target element.
1445           * @method moveToEl
1446           * @param {HTMLElement} moveEl      The element to move
1447           * @param {HTMLElement} targetEl    The position reference element
1448           * @static
1449           */
1450          moveToEl: function (moveEl, targetEl) {
1451              var aCoord = YAHOO.util.Dom.getXY(targetEl);
1452              YAHOO.util.Dom.setXY(moveEl, aCoord);
1453          },
1454  
1455          /**
1456           * Gets the client height
1457           * @method getClientHeight
1458           * @return {int} client height in px
1459           * @deprecated use YAHOO.util.Dom.getViewportHeight instead
1460           * @static
1461           */
1462          getClientHeight: function() {
1463              return YAHOO.util.Dom.getViewportHeight();
1464          },
1465  
1466          /**
1467           * Gets the client width
1468           * @method getClientWidth
1469           * @return {int} client width in px
1470           * @deprecated use YAHOO.util.Dom.getViewportWidth instead
1471           * @static
1472           */
1473          getClientWidth: function() {
1474              return YAHOO.util.Dom.getViewportWidth();
1475          },
1476  
1477          /**
1478           * Numeric array sort function
1479           * @method numericSort
1480           * @static
1481           */
1482          numericSort: function(a, b) { return (a - b); },
1483  
1484          /**
1485           * Internal counter
1486           * @property _timeoutCount
1487           * @private
1488           * @static
1489           */
1490          _timeoutCount: 0,
1491  
1492          /**
1493           * Trying to make the load order less important.  Without this we get
1494           * an error if this file is loaded before the Event Utility.
1495           * @method _addListeners
1496           * @private
1497           * @static
1498           */
1499          _addListeners: function() {
1500              var DDM = YAHOO.util.DDM;
1501              if ( YAHOO.util.Event && document ) {
1502                  DDM._onLoad();
1503              } else {
1504                  if (DDM._timeoutCount > 2000) {
1505                  } else {
1506                      setTimeout(DDM._addListeners, 10);
1507                      if (document && document.body) {
1508                          DDM._timeoutCount += 1;
1509                      }
1510                  }
1511              }
1512          },
1513  
1514          /**
1515           * Recursively searches the immediate parent and all child nodes for 
1516           * the handle element in order to determine wheter or not it was 
1517           * clicked.
1518           * @method handleWasClicked
1519           * @param node the html element to inspect
1520           * @static
1521           */
1522          handleWasClicked: function(node, id) {
1523              if (this.isHandle(id, node.id)) {
1524                  return true;
1525              } else {
1526                  // check to see if this is a text node child of the one we want
1527                  var p = node.parentNode;
1528  
1529                  while (p) {
1530                      if (this.isHandle(id, p.id)) {
1531                          return true;
1532                      } else {
1533                          p = p.parentNode;
1534                      }
1535                  }
1536              }
1537  
1538              return false;
1539          }
1540  
1541      };
1542  
1543  }();
1544  
1545  // shorter alias, save a few bytes
1546  YAHOO.util.DDM = YAHOO.util.DragDropMgr;
1547  YAHOO.util.DDM._addListeners();
1548  
1549  }
1550  
1551  (function() {
1552  
1553  var Event=YAHOO.util.Event; 
1554  var Dom=YAHOO.util.Dom;
1555  
1556  /**
1557   * Defines the interface and base operation of items that that can be 
1558   * dragged or can be drop targets.  It was designed to be extended, overriding
1559   * the event handlers for startDrag, onDrag, onDragOver, onDragOut.
1560   * Up to three html elements can be associated with a DragDrop instance:
1561   * <ul>
1562   * <li>linked element: the element that is passed into the constructor.
1563   * This is the element which defines the boundaries for interaction with 
1564   * other DragDrop objects.</li>
1565   * <li>handle element(s): The drag operation only occurs if the element that 
1566   * was clicked matches a handle element.  By default this is the linked 
1567   * element, but there are times that you will want only a portion of the 
1568   * linked element to initiate the drag operation, and the setHandleElId() 
1569   * method provides a way to define this.</li>
1570   * <li>drag element: this represents an the element that would be moved along
1571   * with the cursor during a drag operation.  By default, this is the linked
1572   * element itself as in {@link YAHOO.util.DD}.  setDragElId() lets you define
1573   * a separate element that would be moved, as in {@link YAHOO.util.DDProxy}
1574   * </li>
1575   * </ul>
1576   * This class should not be instantiated until the onload event to ensure that
1577   * the associated elements are available.
1578   * The following would define a DragDrop obj that would interact with any 
1579   * other DragDrop obj in the "group1" group:
1580   * <pre>
1581   *  dd = new YAHOO.util.DragDrop("div1", "group1");
1582   * </pre>
1583   * Since none of the event handlers have been implemented, nothing would 
1584   * actually happen if you were to run the code above.  Normally you would 
1585   * override this class or one of the default implementations, but you can 
1586   * also override the methods you want on an instance of the class...
1587   * <pre>
1588   *  dd.onDragDrop = function(e, id) {
1589   *  &nbsp;&nbsp;alert("dd was dropped on " + id);
1590   *  }
1591   * </pre>
1592   * @namespace YAHOO.util
1593   * @class DragDrop
1594   * @constructor
1595   * @param {String} id of the element that is linked to this instance
1596   * @param {String} sGroup the group of related DragDrop objects
1597   * @param {object} config an object containing configurable attributes
1598   *                Valid properties for DragDrop: 
1599   *                    padding, isTarget, maintainOffset, primaryButtonOnly,
1600   */
1601  YAHOO.util.DragDrop = function(id, sGroup, config) {
1602      if (id) {
1603          this.init(id, sGroup, config); 
1604      }
1605  };
1606  
1607  YAHOO.util.DragDrop.prototype = {
1608      /**
1609       * An Object Literal containing the events that we will be using: mouseDown, b4MouseDown, mouseUp, b4StartDrag, startDrag, b4EndDrag, endDrag, mouseUp, drag, b4Drag, invalidDrop, b4DragOut, dragOut, dragEnter, b4DragOver, dragOver, b4DragDrop, dragDrop
1610       * By setting any of these to false, then event will not be fired.
1611       * @property events
1612       * @type object
1613       */
1614      events: null,
1615      /**
1616      * @method on
1617      * @description Shortcut for EventProvider.subscribe, see <a href="YAHOO.util.EventProvider.html#subscribe">YAHOO.util.EventProvider.subscribe</a>
1618      */
1619      on: function() {
1620          this.subscribe.apply(this, arguments);
1621      },
1622      /**
1623       * The id of the element associated with this object.  This is what we 
1624       * refer to as the "linked element" because the size and position of 
1625       * this element is used to determine when the drag and drop objects have 
1626       * interacted.
1627       * @property id
1628       * @type String
1629       */
1630      id: null,
1631  
1632      /**
1633       * Configuration attributes passed into the constructor
1634       * @property config
1635       * @type object
1636       */
1637      config: null,
1638  
1639      /**
1640       * The id of the element that will be dragged.  By default this is same 
1641       * as the linked element , but could be changed to another element. Ex: 
1642       * YAHOO.util.DDProxy
1643       * @property dragElId
1644       * @type String
1645       * @private
1646       */
1647      dragElId: null, 
1648  
1649      /**
1650       * the id of the element that initiates the drag operation.  By default 
1651       * this is the linked element, but could be changed to be a child of this
1652       * element.  This lets us do things like only starting the drag when the 
1653       * header element within the linked html element is clicked.
1654       * @property handleElId
1655       * @type String
1656       * @private
1657       */
1658      handleElId: null, 
1659  
1660      /**
1661       * An associative array of HTML tags that will be ignored if clicked.
1662       * @property invalidHandleTypes
1663       * @type {string: string}
1664       */
1665      invalidHandleTypes: null, 
1666  
1667      /**
1668       * An associative array of ids for elements that will be ignored if clicked
1669       * @property invalidHandleIds
1670       * @type {string: string}
1671       */
1672      invalidHandleIds: null, 
1673  
1674      /**
1675       * An indexted array of css class names for elements that will be ignored
1676       * if clicked.
1677       * @property invalidHandleClasses
1678       * @type string[]
1679       */
1680      invalidHandleClasses: null, 
1681  
1682      /**
1683       * The linked element's absolute X position at the time the drag was 
1684       * started
1685       * @property startPageX
1686       * @type int
1687       * @private
1688       */
1689      startPageX: 0,
1690  
1691      /**
1692       * The linked element's absolute X position at the time the drag was 
1693       * started
1694       * @property startPageY
1695       * @type int
1696       * @private
1697       */
1698      startPageY: 0,
1699  
1700      /**
1701       * The group defines a logical collection of DragDrop objects that are 
1702       * related.  Instances only get events when interacting with other 
1703       * DragDrop object in the same group.  This lets us define multiple 
1704       * groups using a single DragDrop subclass if we want.
1705       * @property groups
1706       * @type {string: string}
1707       */
1708      groups: null,
1709  
1710      /**
1711       * Individual drag/drop instances can be locked.  This will prevent 
1712       * onmousedown start drag.
1713       * @property locked
1714       * @type boolean
1715       * @private
1716       */
1717      locked: false,
1718  
1719      /**
1720       * Lock this instance
1721       * @method lock
1722       */
1723      lock: function() { this.locked = true; },
1724  
1725      /**
1726       * Unlock this instace
1727       * @method unlock
1728       */
1729      unlock: function() { this.locked = false; },
1730  
1731      /**
1732       * By default, all instances can be a drop target.  This can be disabled by
1733       * setting isTarget to false.
1734       * @property isTarget
1735       * @type boolean
1736       */
1737      isTarget: true,
1738  
1739      /**
1740       * The padding configured for this drag and drop object for calculating
1741       * the drop zone intersection with this object.
1742       * @property padding
1743       * @type int[]
1744       */
1745      padding: null,
1746      /**
1747       * If this flag is true, do not fire drop events. The element is a drag only element (for movement not dropping)
1748       * @property dragOnly
1749       * @type Boolean
1750       */
1751      dragOnly: false,
1752  
1753      /**
1754       * If this flag is true, a shim will be placed over the screen/viewable area to track mouse events. Should help with dragging elements over iframes and other controls.
1755       * @property useShim
1756       * @type Boolean
1757       */
1758      useShim: false,
1759  
1760      /**
1761       * Cached reference to the linked element
1762       * @property _domRef
1763       * @private
1764       */
1765      _domRef: null,
1766  
1767      /**
1768       * Internal typeof flag
1769       * @property __ygDragDrop
1770       * @private
1771       */
1772      __ygDragDrop: true,
1773  
1774      /**
1775       * Set to true when horizontal contraints are applied
1776       * @property constrainX
1777       * @type boolean
1778       * @private
1779       */
1780      constrainX: false,
1781  
1782      /**
1783       * Set to true when vertical contraints are applied
1784       * @property constrainY
1785       * @type boolean
1786       * @private
1787       */
1788      constrainY: false,
1789  
1790      /**
1791       * The left constraint
1792       * @property minX
1793       * @type int
1794       * @private
1795       */
1796      minX: 0,
1797  
1798      /**
1799       * The right constraint
1800       * @property maxX
1801       * @type int
1802       * @private
1803       */
1804      maxX: 0,
1805  
1806      /**
1807       * The up constraint 
1808       * @property minY
1809       * @type int
1810       * @type int
1811       * @private
1812       */
1813      minY: 0,
1814  
1815      /**
1816       * The down constraint 
1817       * @property maxY
1818       * @type int
1819       * @private
1820       */
1821      maxY: 0,
1822  
1823      /**
1824       * The difference between the click position and the source element's location
1825       * @property deltaX
1826       * @type int
1827       * @private
1828       */
1829      deltaX: 0,
1830  
1831      /**
1832       * The difference between the click position and the source element's location
1833       * @property deltaY
1834       * @type int
1835       * @private
1836       */
1837      deltaY: 0,
1838  
1839      /**
1840       * Maintain offsets when we resetconstraints.  Set to true when you want
1841       * the position of the element relative to its parent to stay the same
1842       * when the page changes
1843       *
1844       * @property maintainOffset
1845       * @type boolean
1846       */
1847      maintainOffset: false,
1848  
1849      /**
1850       * Array of pixel locations the element will snap to if we specified a 
1851       * horizontal graduation/interval.  This array is generated automatically
1852       * when you define a tick interval.
1853       * @property xTicks
1854       * @type int[]
1855       */
1856      xTicks: null,
1857  
1858      /**
1859       * Array of pixel locations the element will snap to if we specified a 
1860       * vertical graduation/interval.  This array is generated automatically 
1861       * when you define a tick interval.
1862       * @property yTicks
1863       * @type int[]
1864       */
1865      yTicks: null,
1866  
1867      /**
1868       * By default the drag and drop instance will only respond to the primary
1869       * button click (left button for a right-handed mouse).  Set to true to
1870       * allow drag and drop to start with any mouse click that is propogated
1871       * by the browser
1872       * @property primaryButtonOnly
1873       * @type boolean
1874       */
1875      primaryButtonOnly: true,
1876  
1877      /**
1878       * The availabe property is false until the linked dom element is accessible.
1879       * @property available
1880       * @type boolean
1881       */
1882      available: false,
1883  
1884      /**
1885       * By default, drags can only be initiated if the mousedown occurs in the
1886       * region the linked element is.  This is done in part to work around a
1887       * bug in some browsers that mis-report the mousedown if the previous
1888       * mouseup happened outside of the window.  This property is set to true
1889       * if outer handles are defined.
1890       *
1891       * @property hasOuterHandles
1892       * @type boolean
1893       * @default false
1894       */
1895      hasOuterHandles: false,
1896  
1897      /**
1898       * Property that is assigned to a drag and drop object when testing to
1899       * see if it is being targeted by another dd object.  This property
1900       * can be used in intersect mode to help determine the focus of
1901       * the mouse interaction.  DDM.getBestMatch uses this property first to
1902       * determine the closest match in INTERSECT mode when multiple targets
1903       * are part of the same interaction.
1904       * @property cursorIsOver
1905       * @type boolean
1906       */
1907      cursorIsOver: false,
1908  
1909      /**
1910       * Property that is assigned to a drag and drop object when testing to
1911       * see if it is being targeted by another dd object.  This is a region
1912       * that represents the area the draggable element overlaps this target.
1913       * DDM.getBestMatch uses this property to compare the size of the overlap
1914       * to that of other targets in order to determine the closest match in
1915       * INTERSECT mode when multiple targets are part of the same interaction.
1916       * @property overlap 
1917       * @type YAHOO.util.Region
1918       */
1919      overlap: null,
1920  
1921      /**
1922       * Code that executes immediately before the startDrag event
1923       * @method b4StartDrag
1924       * @private
1925       */
1926      b4StartDrag: function(x, y) { },
1927  
1928      /**
1929       * Abstract method called after a drag/drop object is clicked
1930       * and the drag or mousedown time thresholds have beeen met.
1931       * @method startDrag
1932       * @param {int} X click location
1933       * @param {int} Y click location
1934       */
1935      startDrag: function(x, y) { /* override this */ },
1936  
1937      /**
1938       * Code that executes immediately before the onDrag event
1939       * @method b4Drag
1940       * @private
1941       */
1942      b4Drag: function(e) { },
1943  
1944      /**
1945       * Abstract method called during the onMouseMove event while dragging an 
1946       * object.
1947       * @method onDrag
1948       * @param {Event} e the mousemove event
1949       */
1950      onDrag: function(e) { /* override this */ },
1951  
1952      /**
1953       * Abstract method called when this element fist begins hovering over 
1954       * another DragDrop obj
1955       * @method onDragEnter
1956       * @param {Event} e the mousemove event
1957       * @param {String|DragDrop[]} id In POINT mode, the element
1958       * id this is hovering over.  In INTERSECT mode, an array of one or more 
1959       * dragdrop items being hovered over.
1960       */
1961      onDragEnter: function(e, id) { /* override this */ },
1962  
1963      /**
1964       * Code that executes immediately before the onDragOver event
1965       * @method b4DragOver
1966       * @private
1967       */
1968      b4DragOver: function(e) { },
1969  
1970      /**
1971       * Abstract method called when this element is hovering over another 
1972       * DragDrop obj
1973       * @method onDragOver
1974       * @param {Event} e the mousemove event
1975       * @param {String|DragDrop[]} id In POINT mode, the element
1976       * id this is hovering over.  In INTERSECT mode, an array of dd items 
1977       * being hovered over.
1978       */
1979      onDragOver: function(e, id) { /* override this */ },
1980  
1981      /**
1982       * Code that executes immediately before the onDragOut event
1983       * @method b4DragOut
1984       * @private
1985       */
1986      b4DragOut: function(e) { },
1987  
1988      /**
1989       * Abstract method called when we are no longer hovering over an element
1990       * @method onDragOut
1991       * @param {Event} e the mousemove event
1992       * @param {String|DragDrop[]} id In POINT mode, the element
1993       * id this was hovering over.  In INTERSECT mode, an array of dd items 
1994       * that the mouse is no longer over.
1995       */
1996      onDragOut: function(e, id) { /* override this */ },
1997  
1998      /**
1999       * Code that executes immediately before the onDragDrop event
2000       * @method b4DragDrop
2001       * @private
2002       */
2003      b4DragDrop: function(e) { },
2004  
2005      /**
2006       * Abstract method called when this item is dropped on another DragDrop 
2007       * obj
2008       * @method onDragDrop
2009       * @param {Event} e the mouseup event
2010       * @param {String|DragDrop[]} id In POINT mode, the element
2011       * id this was dropped on.  In INTERSECT mode, an array of dd items this 
2012       * was dropped on.
2013       */
2014      onDragDrop: function(e, id) { /* override this */ },
2015  
2016      /**
2017       * Abstract method called when this item is dropped on an area with no
2018       * drop target
2019       * @method onInvalidDrop
2020       * @param {Event} e the mouseup event
2021       */
2022      onInvalidDrop: function(e) { /* override this */ },
2023  
2024      /**
2025       * Code that executes immediately before the endDrag event
2026       * @method b4EndDrag
2027       * @private
2028       */
2029      b4EndDrag: function(e) { },
2030  
2031      /**
2032       * Fired when we are done dragging the object
2033       * @method endDrag
2034       * @param {Event} e the mouseup event
2035       */
2036      endDrag: function(e) { /* override this */ },
2037  
2038      /**
2039       * Code executed immediately before the onMouseDown event
2040       * @method b4MouseDown
2041       * @param {Event} e the mousedown event
2042       * @private
2043       */
2044      b4MouseDown: function(e) {  },
2045  
2046      /**
2047       * Event handler that fires when a drag/drop obj gets a mousedown
2048       * @method onMouseDown
2049       * @param {Event} e the mousedown event
2050       */
2051      onMouseDown: function(e) { /* override this */ },
2052  
2053      /**
2054       * Event handler that fires when a drag/drop obj gets a mouseup
2055       * @method onMouseUp
2056       * @param {Event} e the mouseup event
2057       */
2058      onMouseUp: function(e) { /* override this */ },
2059     
2060      /**
2061       * Override the onAvailable method to do what is needed after the initial
2062       * position was determined.
2063       * @method onAvailable
2064       */
2065      onAvailable: function () { 
2066      },
2067  
2068      /**
2069       * Returns a reference to the linked element
2070       * @method getEl
2071       * @return {HTMLElement} the html element 
2072       */
2073      getEl: function() { 
2074          if (!this._domRef) {
2075              this._domRef = Dom.get(this.id); 
2076          }
2077  
2078          return this._domRef;
2079      },
2080  
2081      /**
2082       * Returns a reference to the actual element to drag.  By default this is
2083       * the same as the html element, but it can be assigned to another 
2084       * element. An example of this can be found in YAHOO.util.DDProxy
2085       * @method getDragEl
2086       * @return {HTMLElement} the html element 
2087       */
2088      getDragEl: function() {
2089          return Dom.get(this.dragElId);
2090      },
2091  
2092      /**
2093       * Sets up the DragDrop object.  Must be called in the constructor of any
2094       * YAHOO.util.DragDrop subclass
2095       * @method init
2096       * @param id the id of the linked element
2097       * @param {String} sGroup the group of related items
2098       * @param {object} config configuration attributes
2099       */
2100      init: function(id, sGroup, config) {
2101          this.initTarget(id, sGroup, config);
2102          Event.on(this._domRef || this.id, "mousedown", 
2103                          this.handleMouseDown, this, true);
2104  
2105          // Event.on(this.id, "selectstart", Event.preventDefault);
2106          for (var i in this.events) {
2107              this.createEvent(i + 'Event');
2108          }
2109          
2110      },
2111  
2112      /**
2113       * Initializes Targeting functionality only... the object does not
2114       * get a mousedown handler.
2115       * @method initTarget
2116       * @param id the id of the linked element
2117       * @param {String} sGroup the group of related items
2118       * @param {object} config configuration attributes
2119       */
2120      initTarget: function(id, sGroup, config) {
2121  
2122          // configuration attributes 
2123          this.config = config || {};
2124  
2125          this.events = {};
2126  
2127          // create a local reference to the drag and drop manager
2128          this.DDM = YAHOO.util.DDM;
2129  
2130          // initialize the groups object
2131          this.groups = {};
2132  
2133          // assume that we have an element reference instead of an id if the
2134          // parameter is not a string
2135          if (typeof id !== "string") {
2136              this._domRef = id;
2137              id = Dom.generateId(id);
2138          }
2139  
2140          // set the id
2141          this.id = id;
2142  
2143          // add to an interaction group
2144          this.addToGroup((sGroup) ? sGroup : "default");
2145  
2146          // We don't want to register this as the handle with the manager
2147          // so we just set the id rather than calling the setter.
2148          this.handleElId = id;
2149  
2150          Event.onAvailable(id, this.handleOnAvailable, this, true);
2151  
2152  
2153          // the linked element is the element that gets dragged by default
2154          this.setDragElId(id); 
2155  
2156          // by default, clicked anchors will not start drag operations. 
2157          // @TODO what else should be here?  Probably form fields.
2158          this.invalidHandleTypes = { A: "A" };
2159          this.invalidHandleIds = {};
2160          this.invalidHandleClasses = [];
2161  
2162          this.applyConfig();
2163      },
2164  
2165      /**
2166       * Applies the configuration parameters that were passed into the constructor.
2167       * This is supposed to happen at each level through the inheritance chain.  So
2168       * a DDProxy implentation will execute apply config on DDProxy, DD, and 
2169       * DragDrop in order to get all of the parameters that are available in
2170       * each object.
2171       * @method applyConfig
2172       */
2173      applyConfig: function() {
2174          this.events = {
2175              mouseDown: true,
2176              b4MouseDown: true,
2177              mouseUp: true,
2178              b4StartDrag: true,
2179              startDrag: true,
2180              b4EndDrag: true,
2181              endDrag: true,
2182              drag: true,
2183              b4Drag: true,
2184              invalidDrop: true,
2185              b4DragOut: true,
2186              dragOut: true,
2187              dragEnter: true,
2188              b4DragOver: true,
2189              dragOver: true,
2190              b4DragDrop: true,
2191              dragDrop: true
2192          };
2193          
2194          if (this.config.events) {
2195              for (var i in this.config.events) {
2196                  if (this.config.events[i] === false) {
2197                      this.events[i] = false;
2198                  }
2199              }
2200          }
2201  
2202  
2203          // configurable properties: 
2204          //    padding, isTarget, maintainOffset, primaryButtonOnly
2205          this.padding           = this.config.padding || [0, 0, 0, 0];
2206          this.isTarget          = (this.config.isTarget !== false);
2207          this.maintainOffset    = (this.config.maintainOffset);
2208          this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
2209          this.dragOnly = ((this.config.dragOnly === true) ? true : false);
2210          this.useShim = ((this.config.useShim === true) ? true : false);
2211      },
2212  
2213      /**
2214       * Executed when the linked element is available
2215       * @method handleOnAvailable
2216       * @private
2217       */
2218      handleOnAvailable: function() {
2219          this.available = true;
2220          this.resetConstraints();
2221          this.onAvailable();
2222      },
2223  
2224       /**
2225       * Configures the padding for the target zone in px.  Effectively expands
2226       * (or reduces) the virtual object size for targeting calculations.  
2227       * Supports css-style shorthand; if only one parameter is passed, all sides
2228       * will have that padding, and if only two are passed, the top and bottom
2229       * will have the first param, the left and right the second.
2230       * @method setPadding
2231       * @param {int} iTop    Top pad
2232       * @param {int} iRight  Right pad
2233       * @param {int} iBot    Bot pad
2234       * @param {int} iLeft   Left pad
2235       */
2236      setPadding: function(iTop, iRight, iBot, iLeft) {
2237          // this.padding = [iLeft, iRight, iTop, iBot];
2238          if (!iRight && 0 !== iRight) {
2239              this.padding = [iTop, iTop, iTop, iTop];
2240          } else if (!iBot && 0 !== iBot) {
2241              this.padding = [iTop, iRight, iTop, iRight];
2242          } else {
2243              this.padding = [iTop, iRight, iBot, iLeft];
2244          }
2245      },
2246  
2247      /**
2248       * Stores the initial placement of the linked element.
2249       * @method setInitialPosition
2250       * @param {int} diffX   the X offset, default 0
2251       * @param {int} diffY   the Y offset, default 0
2252       * @private
2253       */
2254      setInitPosition: function(diffX, diffY) {
2255          var el = this.getEl();
2256  
2257          if (!this.DDM.verifyEl(el)) {
2258              if (el && el.style && (el.style.display == 'none')) {
2259              } else {
2260              }
2261              return;
2262          }
2263  
2264          var dx = diffX || 0;
2265          var dy = diffY || 0;
2266  
2267          var p = Dom.getXY( el );
2268  
2269          this.initPageX = p[0] - dx;
2270          this.initPageY = p[1] - dy;
2271  
2272          this.lastPageX = p[0];
2273          this.lastPageY = p[1];
2274  
2275  
2276  
2277          this.setStartPosition(p);
2278      },
2279  
2280      /**
2281       * Sets the start position of the element.  This is set when the obj
2282       * is initialized, the reset when a drag is started.
2283       * @method setStartPosition
2284       * @param pos current position (from previous lookup)
2285       * @private
2286       */
2287      setStartPosition: function(pos) {
2288          var p = pos || Dom.getXY(this.getEl());
2289  
2290          this.deltaSetXY = null;
2291  
2292          this.startPageX = p[0];
2293          this.startPageY = p[1];
2294      },
2295  
2296      /**
2297       * Add this instance to a group of related drag/drop objects.  All 
2298       * instances belong to at least one group, and can belong to as many 
2299       * groups as needed.
2300       * @method addToGroup
2301       * @param sGroup {string} the name of the group
2302       */
2303      addToGroup: function(sGroup) {
2304          this.groups[sGroup] = true;
2305          this.DDM.regDragDrop(this, sGroup);
2306      },
2307  
2308      /**
2309       * Remove's this instance from the supplied interaction group
2310       * @method removeFromGroup
2311       * @param {string}  sGroup  The group to drop
2312       */
2313      removeFromGroup: function(sGroup) {
2314          if (this.groups[sGroup]) {
2315              delete this.groups[sGroup];
2316          }
2317  
2318          this.DDM.removeDDFromGroup(this, sGroup);
2319      },
2320  
2321      /**
2322       * Allows you to specify that an element other than the linked element 
2323       * will be moved with the cursor during a drag
2324       * @method setDragElId
2325       * @param id {string} the id of the element that will be used to initiate the drag
2326       */
2327      setDragElId: function(id) {
2328          this.dragElId = id;
2329      },
2330  
2331      /**
2332       * Allows you to specify a child of the linked element that should be 
2333       * used to initiate the drag operation.  An example of this would be if 
2334       * you have a content div with text and links.  Clicking anywhere in the 
2335       * content area would normally start the drag operation.  Use this method
2336       * to specify that an element inside of the content div is the element 
2337       * that starts the drag operation.
2338       * @method setHandleElId
2339       * @param id {string} the id of the element that will be used to 
2340       * initiate the drag.
2341       */
2342      setHandleElId: function(id) {
2343          if (typeof id !== "string") {
2344              id = Dom.generateId(id);
2345          }
2346          this.handleElId = id;
2347          this.DDM.regHandle(this.id, id);
2348      },
2349  
2350      /**
2351       * Allows you to set an element outside of the linked element as a drag 
2352       * handle
2353       * @method setOuterHandleElId
2354       * @param id the id of the element that will be used to initiate the drag
2355       */
2356      setOuterHandleElId: function(id) {
2357          if (typeof id !== "string") {
2358              id = Dom.generateId(id);
2359          }
2360          Event.on(id, "mousedown", 
2361                  this.handleMouseDown, this, true);
2362          this.setHandleElId(id);
2363  
2364          this.hasOuterHandles = true;
2365      },
2366  
2367      /**
2368       * Remove all drag and drop hooks for this element
2369       * @method unreg
2370       */
2371      unreg: function() {
2372          Event.removeListener(this.id, "mousedown", 
2373                  this.handleMouseDown);
2374          this._domRef = null;
2375          this.DDM._remove(this);
2376      },
2377  
2378      /**
2379       * Returns true if this instance is locked, or the drag drop mgr is locked
2380       * (meaning that all drag/drop is disabled on the page.)
2381       * @method isLocked
2382       * @return {boolean} true if this obj or all drag/drop is locked, else 
2383       * false
2384       */
2385      isLocked: function() {
2386          return (this.DDM.isLocked() || this.locked);
2387      },
2388  
2389      /**
2390       * Fired when this object is clicked
2391       * @method handleMouseDown
2392       * @param {Event} e 
2393       * @param {YAHOO.util.DragDrop} oDD the clicked dd object (this dd obj)
2394       * @private
2395       */
2396      handleMouseDown: function(e, oDD) {
2397  
2398          var button = e.which || e.button;
2399  
2400          if (this.primaryButtonOnly && button > 1) {
2401              return;
2402          }
2403  
2404          if (this.isLocked()) {
2405              return;
2406          }
2407  
2408  
2409  
2410          // firing the mousedown events prior to calculating positions
2411          var b4Return = this.b4MouseDown(e),
2412          b4Return2 = true;
2413  
2414          if (this.events.b4MouseDown) {
2415              b4Return2 = this.fireEvent('b4MouseDownEvent', e);
2416          }
2417          var mDownReturn = this.onMouseDown(e),
2418              mDownReturn2 = true;
2419          if (this.events.mouseDown) {
2420              if (mDownReturn === false) {
2421                  //Fixes #2528759 - Mousedown function returned false, don't fire the event and cancel everything.
2422                   mDownReturn2 = false;
2423              } else {
2424                  mDownReturn2 = this.fireEvent('mouseDownEvent', e);
2425              }
2426          }
2427  
2428          if ((b4Return === false) || (mDownReturn === false) || (b4Return2 === false) || (mDownReturn2 === false)) {
2429              return;
2430          }
2431  
2432          this.DDM.refreshCache(this.groups);
2433          // var self = this;
2434          // setTimeout( function() { self.DDM.refreshCache(self.groups); }, 0);
2435  
2436          // Only process the event if we really clicked within the linked 
2437          // element.  The reason we make this check is that in the case that 
2438          // another element was moved between the clicked element and the 
2439          // cursor in the time between the mousedown and mouseup events. When 
2440          // this happens, the element gets the next mousedown event 
2441          // regardless of where on the screen it happened.  
2442          var pt = new YAHOO.util.Point(Event.getPageX(e), Event.getPageY(e));
2443          if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
2444          } else {
2445              if (this.clickValidator(e)) {
2446  
2447  
2448                  // set the initial element position
2449                  this.setStartPosition();
2450  
2451                  // start tracking mousemove distance and mousedown time to
2452                  // determine when to start the actual drag
2453                  this.DDM.handleMouseDown(e, this);
2454  
2455                  // this mousedown is mine
2456                  this.DDM.stopEvent(e);
2457              } else {
2458  
2459  
2460              }
2461          }
2462      },
2463  
2464      /**
2465       * @method clickValidator
2466       * @description Method validates that the clicked element
2467       * was indeed the handle or a valid child of the handle
2468       * @param {Event} e 
2469       */
2470      clickValidator: function(e) {
2471          var target = YAHOO.util.Event.getTarget(e);
2472          return ( this.isValidHandleChild(target) &&
2473                      (this.id == this.handleElId || 
2474                          this.DDM.handleWasClicked(target, this.id)) );
2475      },
2476  
2477      /**
2478       * Finds the location the element should be placed if we want to move
2479       * it to where the mouse location less the click offset would place us.
2480       * @method getTargetCoord
2481       * @param {int} iPageX the X coordinate of the click
2482       * @param {int} iPageY the Y coordinate of the click
2483       * @return an object that contains the coordinates (Object.x and Object.y)
2484       * @private
2485       */
2486      getTargetCoord: function(iPageX, iPageY) {
2487  
2488  
2489          var x = iPageX - this.deltaX;
2490          var y = iPageY - this.deltaY;
2491  
2492          if (this.constrainX) {
2493              if (x < this.minX) { x = this.minX; }
2494              if (x > this.maxX) { x = this.maxX; }
2495          }
2496  
2497          if (this.constrainY) {
2498              if (y < this.minY) { y = this.minY; }
2499              if (y > this.maxY) { y = this.maxY; }
2500          }
2501  
2502          x = this.getTick(x, this.xTicks);
2503          y = this.getTick(y, this.yTicks);
2504  
2505  
2506          return {x:x, y:y};
2507      },
2508  
2509      /**
2510       * Allows you to specify a tag name that should not start a drag operation
2511       * when clicked.  This is designed to facilitate embedding links within a
2512       * drag handle that do something other than start the drag.
2513       * @method addInvalidHandleType
2514       * @param {string} tagName the type of element to exclude
2515       */
2516      addInvalidHandleType: function(tagName) {
2517          var type = tagName.toUpperCase();
2518          this.invalidHandleTypes[type] = type;
2519      },
2520  
2521      /**
2522       * Lets you to specify an element id for a child of a drag handle
2523       * that should not initiate a drag
2524       * @method addInvalidHandleId
2525       * @param {string} id the element id of the element you wish to ignore
2526       */
2527      addInvalidHandleId: function(id) {
2528          if (typeof id !== "string") {
2529              id = Dom.generateId(id);
2530          }
2531          this.invalidHandleIds[id] = id;
2532      },
2533  
2534  
2535      /**
2536       * Lets you specify a css class of elements that will not initiate a drag
2537       * @method addInvalidHandleClass
2538       * @param {string} cssClass the class of the elements you wish to ignore
2539       */
2540      addInvalidHandleClass: function(cssClass) {
2541          this.invalidHandleClasses.push(cssClass);
2542      },
2543  
2544      /**
2545       * Unsets an excluded tag name set by addInvalidHandleType
2546       * @method removeInvalidHandleType
2547       * @param {string} tagName the type of element to unexclude
2548       */
2549      removeInvalidHandleType: function(tagName) {
2550          var type = tagName.toUpperCase();
2551          // this.invalidHandleTypes[type] = null;
2552          delete this.invalidHandleTypes[type];
2553      },
2554      
2555      /**
2556       * Unsets an invalid handle id
2557       * @method removeInvalidHandleId
2558       * @param {string} id the id of the element to re-enable
2559       */
2560      removeInvalidHandleId: function(id) {
2561          if (typeof id !== "string") {
2562              id = Dom.generateId(id);
2563          }
2564          delete this.invalidHandleIds[id];
2565      },
2566  
2567      /**
2568       * Unsets an invalid css class
2569       * @method removeInvalidHandleClass
2570       * @param {string} cssClass the class of the element(s) you wish to 
2571       * re-enable
2572       */
2573      removeInvalidHandleClass: function(cssClass) {
2574          for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
2575              if (this.invalidHandleClasses[i] == cssClass) {
2576                  delete this.invalidHandleClasses[i];
2577              }
2578          }
2579      },
2580  
2581      /**
2582       * Checks the tag exclusion list to see if this click should be ignored
2583       * @method isValidHandleChild
2584       * @param {HTMLElement} node the HTMLElement to evaluate
2585       * @return {boolean} true if this is a valid tag type, false if not
2586       */
2587      isValidHandleChild: function(node) {
2588  
2589          var valid = true;
2590          // var n = (node.nodeName == "#text") ? node.parentNode : node;
2591          var nodeName;
2592          try {
2593              nodeName = node.nodeName.toUpperCase();
2594          } catch(e) {
2595              nodeName = node.nodeName;
2596          }
2597          valid = valid && !this.invalidHandleTypes[nodeName];
2598          valid = valid && !this.invalidHandleIds[node.id];
2599  
2600          for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
2601              valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
2602          }
2603  
2604  
2605          return valid;
2606  
2607      },
2608  
2609      /**
2610       * Create the array of horizontal tick marks if an interval was specified
2611       * in setXConstraint().
2612       * @method setXTicks
2613       * @private
2614       */
2615      setXTicks: function(iStartX, iTickSize) {
2616          this.xTicks = [];
2617          this.xTickSize = iTickSize;
2618          
2619          var tickMap = {};
2620  
2621          for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
2622              if (!tickMap[i]) {
2623                  this.xTicks[this.xTicks.length] = i;
2624                  tickMap[i] = true;
2625              }
2626          }
2627  
2628          for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
2629              if (!tickMap[i]) {
2630                  this.xTicks[this.xTicks.length] = i;
2631                  tickMap[i] = true;
2632              }
2633          }
2634  
2635          this.xTicks.sort(this.DDM.numericSort) ;
2636      },
2637  
2638      /**
2639       * Create the array of vertical tick marks if an interval was specified in 
2640       * setYConstraint().
2641       * @method setYTicks
2642       * @private
2643       */
2644      setYTicks: function(iStartY, iTickSize) {
2645          this.yTicks = [];
2646          this.yTickSize = iTickSize;
2647  
2648          var tickMap = {};
2649  
2650          for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
2651              if (!tickMap[i]) {
2652                  this.yTicks[this.yTicks.length] = i;
2653                  tickMap[i] = true;
2654              }
2655          }
2656  
2657          for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
2658              if (!tickMap[i]) {
2659                  this.yTicks[this.yTicks.length] = i;
2660                  tickMap[i] = true;
2661              }
2662          }
2663  
2664          this.yTicks.sort(this.DDM.numericSort) ;
2665      },
2666  
2667      /**
2668       * By default, the element can be dragged any place on the screen.  Use 
2669       * this method to limit the horizontal travel of the element.  Pass in 
2670       * 0,0 for the parameters if you want to lock the drag to the y axis.
2671       * @method setXConstraint
2672       * @param {int} iLeft the number of pixels the element can move to the left
2673       * @param {int} iRight the number of pixels the element can move to the 
2674       * right
2675       * @param {int} iTickSize optional parameter for specifying that the 
2676       * element
2677       * should move iTickSize pixels at a time.
2678       */
2679      setXConstraint: function(iLeft, iRight, iTickSize) {
2680          this.leftConstraint = parseInt(iLeft, 10);
2681          this.rightConstraint = parseInt(iRight, 10);
2682  
2683          this.minX = this.initPageX - this.leftConstraint;
2684          this.maxX = this.initPageX + this.rightConstraint;
2685          if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
2686  
2687          this.constrainX = true;
2688      },
2689  
2690      /**
2691       * Clears any constraints applied to this instance.  Also clears ticks
2692       * since they can't exist independent of a constraint at this time.
2693       * @method clearConstraints
2694       */
2695      clearConstraints: function() {
2696          this.constrainX = false;
2697          this.constrainY = false;
2698          this.clearTicks();
2699      },
2700  
2701      /**
2702       * Clears any tick interval defined for this instance
2703       * @method clearTicks
2704       */
2705      clearTicks: function() {
2706          this.xTicks = null;
2707          this.yTicks = null;
2708          this.xTickSize = 0;
2709          this.yTickSize = 0;
2710      },
2711  
2712      /**
2713       * By default, the element can be dragged any place on the screen.  Set 
2714       * this to limit the vertical travel of the element.  Pass in 0,0 for the
2715       * parameters if you want to lock the drag to the x axis.
2716       * @method setYConstraint
2717       * @param {int} iUp the number of pixels the element can move up
2718       * @param {int} iDown the number of pixels the element can move down
2719       * @param {int} iTickSize optional parameter for specifying that the 
2720       * element should move iTickSize pixels at a time.
2721       */
2722      setYConstraint: function(iUp, iDown, iTickSize) {
2723          this.topConstraint = parseInt(iUp, 10);
2724          this.bottomConstraint = parseInt(iDown, 10);
2725  
2726          this.minY = this.initPageY - this.topConstraint;
2727          this.maxY = this.initPageY + this.bottomConstraint;
2728          if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
2729  
2730          this.constrainY = true;
2731          
2732      },
2733  
2734      /**
2735       * resetConstraints must be called if you manually reposition a dd element.
2736       * @method resetConstraints
2737       */
2738      resetConstraints: function() {
2739  
2740  
2741          // Maintain offsets if necessary
2742          if (this.initPageX || this.initPageX === 0) {
2743              // figure out how much this thing has moved
2744              var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
2745              var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
2746  
2747              this.setInitPosition(dx, dy);
2748  
2749          // This is the first time we have detected the element's position
2750          } else {
2751              this.setInitPosition();
2752          }
2753  
2754          if (this.constrainX) {
2755              this.setXConstraint( this.leftConstraint, 
2756                                   this.rightConstraint, 
2757                                   this.xTickSize        );
2758          }
2759  
2760          if (this.constrainY) {
2761              this.setYConstraint( this.topConstraint, 
2762                                   this.bottomConstraint, 
2763                                   this.yTickSize         );
2764          }
2765      },
2766  
2767      /**
2768       * Normally the drag element is moved pixel by pixel, but we can specify 
2769       * that it move a number of pixels at a time.  This method resolves the 
2770       * location when we have it set up like this.
2771       * @method getTick
2772       * @param {int} val where we want to place the object
2773       * @param {int[]} tickArray sorted array of valid points
2774       * @return {int} the closest tick
2775       * @private
2776       */
2777      getTick: function(val, tickArray) {
2778  
2779          if (!tickArray) {
2780              // If tick interval is not defined, it is effectively 1 pixel, 
2781              // so we return the value passed to us.
2782              return val; 
2783          } else if (tickArray[0] >= val) {
2784              // The value is lower than the first tick, so we return the first
2785              // tick.
2786              return tickArray[0];
2787          } else {
2788              for (var i=0, len=tickArray.length; i<len; ++i) {
2789                  var next = i + 1;
2790                  if (tickArray[next] && tickArray[next] >= val) {
2791                      var diff1 = val - tickArray[i];
2792                      var diff2 = tickArray[next] - val;
2793                      return (diff2 > diff1) ? tickArray[i] : tickArray[next];
2794                  }
2795              }
2796  
2797              // The value is larger than the last tick, so we return the last
2798              // tick.
2799              return tickArray[tickArray.length - 1];
2800          }
2801      },
2802  
2803      /**
2804       * toString method
2805       * @method toString
2806       * @return {string} string representation of the dd obj
2807       */
2808      toString: function() {
2809          return ("DragDrop " + this.id);
2810      }
2811  
2812  };
2813  YAHOO.augment(YAHOO.util.DragDrop, YAHOO.util.EventProvider);
2814  
2815  /**
2816  * @event mouseDownEvent
2817  * @description Provides access to the mousedown event. The mousedown does not always result in a drag operation.
2818  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
2819  */
2820  
2821  /**
2822  * @event b4MouseDownEvent
2823  * @description Provides access to the mousedown event, before the mouseDownEvent gets fired. Returning false will cancel the drag.
2824  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
2825  */
2826  
2827  /**
2828  * @event mouseUpEvent
2829  * @description Fired from inside DragDropMgr when the drag operation is finished.
2830  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
2831  */
2832  
2833  /**
2834  * @event b4StartDragEvent
2835  * @description Fires before the startDragEvent, returning false will cancel the startDrag Event.
2836  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
2837  */
2838  
2839  /**
2840  * @event startDragEvent
2841  * @description Occurs after a mouse down and the drag threshold has been met. The drag threshold default is either 3 pixels of mouse movement or 1 full second of holding the mousedown. 
2842  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
2843  */
2844  
2845  /**
2846  * @event b4EndDragEvent
2847  * @description Fires before the endDragEvent. Returning false will cancel.
2848  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
2849  */
2850  
2851  /**
2852  * @event endDragEvent
2853  * @description Fires on the mouseup event after a drag has been initiated (startDrag fired).
2854  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
2855  */
2856  
2857  /**
2858  * @event dragEvent
2859  * @description Occurs every mousemove event while dragging.
2860  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
2861  */
2862  /**
2863  * @event b4DragEvent
2864  * @description Fires before the dragEvent.
2865  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
2866  */
2867  /**
2868  * @event invalidDropEvent
2869  * @description Fires when the dragged objects is dropped in a location that contains no drop targets.
2870  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
2871  */
2872  /**
2873  * @event b4DragOutEvent
2874  * @description Fires before the dragOutEvent
2875  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
2876  */
2877  /**
2878  * @event dragOutEvent
2879  * @description Fires when a dragged object is no longer over an object that had the onDragEnter fire. 
2880  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
2881  */
2882  /**
2883  * @event dragEnterEvent
2884  * @description Occurs when the dragged object first interacts with another targettable drag and drop object.
2885  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
2886  */
2887  /**
2888  * @event b4DragOverEvent
2889  * @description Fires before the dragOverEvent.
2890  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
2891  */
2892  /**
2893  * @event dragOverEvent
2894  * @description Fires every mousemove event while over a drag and drop object.
2895  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
2896  */
2897  /**
2898  * @event b4DragDropEvent 
2899  * @description Fires before the dragDropEvent
2900  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
2901  */
2902  /**
2903  * @event dragDropEvent
2904  * @description Fires when the dragged objects is dropped on another.
2905  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
2906  */
2907  })();
2908  /**
2909   * A DragDrop implementation where the linked element follows the 
2910   * mouse cursor during a drag.
2911   * @class DD
2912   * @extends YAHOO.util.DragDrop
2913   * @constructor
2914   * @param {String} id the id of the linked element 
2915   * @param {String} sGroup the group of related DragDrop items
2916   * @param {object} config an object containing configurable attributes
2917   *                Valid properties for DD: 
2918   *                    scroll
2919   */
2920  YAHOO.util.DD = function(id, sGroup, config) {
2921      if (id) {
2922          this.init(id, sGroup, config);
2923      }
2924  };
2925  
2926  YAHOO.extend(YAHOO.util.DD, YAHOO.util.DragDrop, {
2927  
2928      /**
2929       * When set to true, the utility automatically tries to scroll the browser
2930       * window when a drag and drop element is dragged near the viewport boundary.
2931       * Defaults to true.
2932       * @property scroll
2933       * @type boolean
2934       */
2935      scroll: true, 
2936  
2937      /**
2938       * Sets the pointer offset to the distance between the linked element's top 
2939       * left corner and the location the element was clicked
2940       * @method autoOffset
2941       * @param {int} iPageX the X coordinate of the click
2942       * @param {int} iPageY the Y coordinate of the click
2943       */
2944      autoOffset: function(iPageX, iPageY) {
2945          var x = iPageX - this.startPageX;
2946          var y = iPageY - this.startPageY;
2947          this.setDelta(x, y);
2948      },
2949  
2950      /** 
2951       * Sets the pointer offset.  You can call this directly to force the 
2952       * offset to be in a particular location (e.g., pass in 0,0 to set it 
2953       * to the center of the object, as done in YAHOO.widget.Slider)
2954       * @method setDelta
2955       * @param {int} iDeltaX the distance from the left
2956       * @param {int} iDeltaY the distance from the top
2957       */
2958      setDelta: function(iDeltaX, iDeltaY) {
2959          this.deltaX = iDeltaX;
2960          this.deltaY = iDeltaY;
2961      },
2962  
2963      /**
2964       * Sets the drag element to the location of the mousedown or click event, 
2965       * maintaining the cursor location relative to the location on the element 
2966       * that was clicked.  Override this if you want to place the element in a 
2967       * location other than where the cursor is.
2968       * @method setDragElPos
2969       * @param {int} iPageX the X coordinate of the mousedown or drag event
2970       * @param {int} iPageY the Y coordinate of the mousedown or drag event
2971       */
2972      setDragElPos: function(iPageX, iPageY) {
2973          // the first time we do this, we are going to check to make sure
2974          // the element has css positioning
2975  
2976          var el = this.getDragEl();
2977          this.alignElWithMouse(el, iPageX, iPageY);
2978      },
2979  
2980      /**
2981       * Sets the element to the location of the mousedown or click event, 
2982       * maintaining the cursor location relative to the location on the element 
2983       * that was clicked.  Override this if you want to place the element in a 
2984       * location other than where the cursor is.
2985       * @method alignElWithMouse
2986       * @param {HTMLElement} el the element to move
2987       * @param {int} iPageX the X coordinate of the mousedown or drag event
2988       * @param {int} iPageY the Y coordinate of the mousedown or drag event
2989       */
2990      alignElWithMouse: function(el, iPageX, iPageY) {
2991          var oCoord = this.getTargetCoord(iPageX, iPageY);
2992  
2993          if (!this.deltaSetXY) {
2994              var aCoord = [oCoord.x, oCoord.y];
2995              YAHOO.util.Dom.setXY(el, aCoord);
2996  
2997              var newLeft = parseInt( YAHOO.util.Dom.getStyle(el, "left"), 10 );
2998              var newTop  = parseInt( YAHOO.util.Dom.getStyle(el, "top" ), 10 );
2999  
3000              this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
3001          } else {
3002              YAHOO.util.Dom.setStyle(el, "left", (oCoord.x + this.deltaSetXY[0]) + "px");
3003              YAHOO.util.Dom.setStyle(el, "top",  (oCoord.y + this.deltaSetXY[1]) + "px");
3004          }
3005          
3006          this.cachePosition(oCoord.x, oCoord.y);
3007          var self = this;
3008          setTimeout(function() {
3009              self.autoScroll.call(self, oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
3010          }, 0);
3011      },
3012  
3013      /**
3014       * Saves the most recent position so that we can reset the constraints and
3015       * tick marks on-demand.  We need to know this so that we can calculate the
3016       * number of pixels the element is offset from its original position.
3017       * @method cachePosition
3018       * @param iPageX the current x position (optional, this just makes it so we
3019       * don't have to look it up again)
3020       * @param iPageY the current y position (optional, this just makes it so we
3021       * don't have to look it up again)
3022       */
3023      cachePosition: function(iPageX, iPageY) {
3024          if (iPageX) {
3025              this.lastPageX = iPageX;
3026              this.lastPageY = iPageY;
3027          } else {
3028              var aCoord = YAHOO.util.Dom.getXY(this.getEl());
3029              this.lastPageX = aCoord[0];
3030              this.lastPageY = aCoord[1];
3031          }
3032      },
3033  
3034      /**
3035       * Auto-scroll the window if the dragged object has been moved beyond the 
3036       * visible window boundary.
3037       * @method autoScroll
3038       * @param {int} x the drag element's x position
3039       * @param {int} y the drag element's y position
3040       * @param {int} h the height of the drag element
3041       * @param {int} w the width of the drag element
3042       * @private
3043       */
3044      autoScroll: function(x, y, h, w) {
3045  
3046          if (this.scroll) {
3047              // The client height
3048              var clientH = this.DDM.getClientHeight();
3049  
3050              // The client width
3051              var clientW = this.DDM.getClientWidth();
3052  
3053              // The amt scrolled down
3054              var st = this.DDM.getScrollTop();
3055  
3056              // The amt scrolled right
3057              var sl = this.DDM.getScrollLeft();
3058  
3059              // Location of the bottom of the element
3060              var bot = h + y;
3061  
3062              // Location of the right of the element
3063              var right = w + x;
3064  
3065              // The distance from the cursor to the bottom of the visible area, 
3066              // adjusted so that we don't scroll if the cursor is beyond the
3067              // element drag constraints
3068              var toBot = (clientH + st - y - this.deltaY);
3069  
3070              // The distance from the cursor to the right of the visible area
3071              var toRight = (clientW + sl - x - this.deltaX);
3072  
3073  
3074              // How close to the edge the cursor must be before we scroll
3075              // var thresh = (document.all) ? 100 : 40;
3076              var thresh = 40;
3077  
3078              // How many pixels to scroll per autoscroll op.  This helps to reduce 
3079              // clunky scrolling. IE is more sensitive about this ... it needs this 
3080              // value to be higher.
3081              var scrAmt = (document.all) ? 80 : 30;
3082  
3083              // Scroll down if we are near the bottom of the visible page and the 
3084              // obj extends below the crease
3085              if ( bot > clientH && toBot < thresh ) { 
3086                  window.scrollTo(sl, st + scrAmt); 
3087              }
3088  
3089              // Scroll up if the window is scrolled down and the top of the object
3090              // goes above the top border
3091              if ( y < st && st > 0 && y - st < thresh ) { 
3092                  window.scrollTo(sl, st - scrAmt); 
3093              }
3094  
3095              // Scroll right if the obj is beyond the right border and the cursor is
3096              // near the border.
3097              if ( right > clientW && toRight < thresh ) { 
3098                  window.scrollTo(sl + scrAmt, st); 
3099              }
3100  
3101              // Scroll left if the window has been scrolled to the right and the obj
3102              // extends past the left border
3103              if ( x < sl && sl > 0 && x - sl < thresh ) { 
3104                  window.scrollTo(sl - scrAmt, st);
3105              }
3106          }
3107      },
3108  
3109      /*
3110       * Sets up config options specific to this class. Overrides
3111       * YAHOO.util.DragDrop, but all versions of this method through the 
3112       * inheritance chain are called
3113       */
3114      applyConfig: function() {
3115          YAHOO.util.DD.superclass.applyConfig.call(this);
3116          this.scroll = (this.config.scroll !== false);
3117      },
3118  
3119      /*
3120       * Event that fires prior to the onMouseDown event.  Overrides 
3121       * YAHOO.util.DragDrop.
3122       */
3123      b4MouseDown: function(e) {
3124          this.setStartPosition();
3125          // this.resetConstraints();
3126          this.autoOffset(YAHOO.util.Event.getPageX(e), 
3127                              YAHOO.util.Event.getPageY(e));
3128      },
3129  
3130      /*
3131       * Event that fires prior to the onDrag event.  Overrides 
3132       * YAHOO.util.DragDrop.
3133       */
3134      b4Drag: function(e) {
3135          this.setDragElPos(YAHOO.util.Event.getPageX(e), 
3136                              YAHOO.util.Event.getPageY(e));
3137      },
3138  
3139      toString: function() {
3140          return ("DD " + this.id);
3141      }
3142  
3143      //////////////////////////////////////////////////////////////////////////
3144      // Debugging ygDragDrop events that can be overridden
3145      //////////////////////////////////////////////////////////////////////////
3146      /*
3147      startDrag: function(x, y) {
3148      },
3149  
3150      onDrag: function(e) {
3151      },
3152  
3153      onDragEnter: function(e, id) {
3154      },
3155  
3156      onDragOver: function(e, id) {
3157      },
3158  
3159      onDragOut: function(e, id) {
3160      },
3161  
3162      onDragDrop: function(e, id) {
3163      },
3164  
3165      endDrag: function(e) {
3166      }
3167  
3168      */
3169  
3170  /**
3171  * @event mouseDownEvent
3172  * @description Provides access to the mousedown event. The mousedown does not always result in a drag operation.
3173  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3174  */
3175  
3176  /**
3177  * @event b4MouseDownEvent
3178  * @description Provides access to the mousedown event, before the mouseDownEvent gets fired. Returning false will cancel the drag.
3179  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3180  */
3181  
3182  /**
3183  * @event mouseUpEvent
3184  * @description Fired from inside DragDropMgr when the drag operation is finished.
3185  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3186  */
3187  
3188  /**
3189  * @event b4StartDragEvent
3190  * @description Fires before the startDragEvent, returning false will cancel the startDrag Event.
3191  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3192  */
3193  
3194  /**
3195  * @event startDragEvent
3196  * @description Occurs after a mouse down and the drag threshold has been met. The drag threshold default is either 3 pixels of mouse movement or 1 full second of holding the mousedown. 
3197  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3198  */
3199  
3200  /**
3201  * @event b4EndDragEvent
3202  * @description Fires before the endDragEvent. Returning false will cancel.
3203  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3204  */
3205  
3206  /**
3207  * @event endDragEvent
3208  * @description Fires on the mouseup event after a drag has been initiated (startDrag fired).
3209  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3210  */
3211  
3212  /**
3213  * @event dragEvent
3214  * @description Occurs every mousemove event while dragging.
3215  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3216  */
3217  /**
3218  * @event b4DragEvent
3219  * @description Fires before the dragEvent.
3220  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3221  */
3222  /**
3223  * @event invalidDropEvent
3224  * @description Fires when the dragged objects is dropped in a location that contains no drop targets.
3225  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3226  */
3227  /**
3228  * @event b4DragOutEvent
3229  * @description Fires before the dragOutEvent
3230  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3231  */
3232  /**
3233  * @event dragOutEvent
3234  * @description Fires when a dragged object is no longer over an object that had the onDragEnter fire. 
3235  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3236  */
3237  /**
3238  * @event dragEnterEvent
3239  * @description Occurs when the dragged object first interacts with another targettable drag and drop object.
3240  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3241  */
3242  /**
3243  * @event b4DragOverEvent
3244  * @description Fires before the dragOverEvent.
3245  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3246  */
3247  /**
3248  * @event dragOverEvent
3249  * @description Fires every mousemove event while over a drag and drop object.
3250  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3251  */
3252  /**
3253  * @event b4DragDropEvent 
3254  * @description Fires before the dragDropEvent
3255  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3256  */
3257  /**
3258  * @event dragDropEvent
3259  * @description Fires when the dragged objects is dropped on another.
3260  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3261  */
3262  });
3263  /**
3264   * A DragDrop implementation that inserts an empty, bordered div into
3265   * the document that follows the cursor during drag operations.  At the time of
3266   * the click, the frame div is resized to the dimensions of the linked html
3267   * element, and moved to the exact location of the linked element.
3268   *
3269   * References to the "frame" element refer to the single proxy element that
3270   * was created to be dragged in place of all DDProxy elements on the
3271   * page.
3272   *
3273   * @class DDProxy
3274   * @extends YAHOO.util.DD
3275   * @constructor
3276   * @param {String} id the id of the linked html element
3277   * @param {String} sGroup the group of related DragDrop objects
3278   * @param {object} config an object containing configurable attributes
3279   *                Valid properties for DDProxy in addition to those in DragDrop: 
3280   *                   resizeFrame, centerFrame, dragElId
3281   */
3282  YAHOO.util.DDProxy = function(id, sGroup, config) {
3283      if (id) {
3284          this.init(id, sGroup, config);
3285          this.initFrame(); 
3286      }
3287  };
3288  
3289  /**
3290   * The default drag frame div id
3291   * @property YAHOO.util.DDProxy.dragElId
3292   * @type String
3293   * @static
3294   */
3295  YAHOO.util.DDProxy.dragElId = "ygddfdiv";
3296  
3297  YAHOO.extend(YAHOO.util.DDProxy, YAHOO.util.DD, {
3298  
3299      /**
3300       * By default we resize the drag frame to be the same size as the element
3301       * we want to drag (this is to get the frame effect).  We can turn it off
3302       * if we want a different behavior.
3303       * @property resizeFrame
3304       * @type boolean
3305       */
3306      resizeFrame: true,
3307  
3308      /**
3309       * By default the frame is positioned exactly where the drag element is, so
3310       * we use the cursor offset provided by YAHOO.util.DD.  Another option that works only if
3311       * you do not have constraints on the obj is to have the drag frame centered
3312       * around the cursor.  Set centerFrame to true for this effect.
3313       * @property centerFrame
3314       * @type boolean
3315       */
3316      centerFrame: false,
3317  
3318      /**
3319       * Creates the proxy element if it does not yet exist
3320       * @method createFrame
3321       */
3322      createFrame: function() {
3323          var self=this, body=document.body;
3324  
3325          if (!body || !body.firstChild) {
3326              setTimeout( function() { self.createFrame(); }, 50 );
3327              return;
3328          }
3329  
3330          var div=this.getDragEl(), Dom=YAHOO.util.Dom;
3331  
3332          if (!div) {
3333              div    = document.createElement("div");
3334              div.id = this.dragElId;
3335              var s  = div.style;
3336  
3337              s.position   = "absolute";
3338              s.visibility = "hidden";
3339              s.cursor     = "move";
3340              s.border     = "2px solid #aaa";
3341              s.zIndex     = 999;
3342              s.height     = "25px";
3343              s.width      = "25px";
3344  
3345              var _data = document.createElement('div');
3346              Dom.setStyle(_data, 'height', '100%');
3347              Dom.setStyle(_data, 'width', '100%');
3348              /**
3349              * If the proxy element has no background-color, then it is considered to the "transparent" by Internet Explorer.
3350              * Since it is "transparent" then the events pass through it to the iframe below.
3351              * So creating a "fake" div inside the proxy element and giving it a background-color, then setting it to an
3352              * opacity of 0, it appears to not be there, however IE still thinks that it is so the events never pass through.
3353              */
3354              Dom.setStyle(_data, 'background-color', '#ccc');
3355              Dom.setStyle(_data, 'opacity', '0');
3356              div.appendChild(_data);
3357  
3358              // appendChild can blow up IE if invoked prior to the window load event
3359              // while rendering a table.  It is possible there are other scenarios 
3360              // that would cause this to happen as well.
3361              body.insertBefore(div, body.firstChild);
3362          }
3363      },
3364  
3365      /**
3366       * Initialization for the drag frame element.  Must be called in the
3367       * constructor of all subclasses
3368       * @method initFrame
3369       */
3370      initFrame: function() {
3371          this.createFrame();
3372      },
3373  
3374      applyConfig: function() {
3375          YAHOO.util.DDProxy.superclass.applyConfig.call(this);
3376  
3377          this.resizeFrame = (this.config.resizeFrame !== false);
3378          this.centerFrame = (this.config.centerFrame);
3379          this.setDragElId(this.config.dragElId || YAHOO.util.DDProxy.dragElId);
3380      },
3381  
3382      /**
3383       * Resizes the drag frame to the dimensions of the clicked object, positions 
3384       * it over the object, and finally displays it
3385       * @method showFrame
3386       * @param {int} iPageX X click position
3387       * @param {int} iPageY Y click position
3388       * @private
3389       */
3390      showFrame: function(iPageX, iPageY) {
3391          var el = this.getEl();
3392          var dragEl = this.getDragEl();
3393          var s = dragEl.style;
3394  
3395          this._resizeProxy();
3396  
3397          if (this.centerFrame) {
3398              this.setDelta( Math.round(parseInt(s.width,  10)/2), 
3399                             Math.round(parseInt(s.height, 10)/2) );
3400          }
3401  
3402          this.setDragElPos(iPageX, iPageY);
3403  
3404          YAHOO.util.Dom.setStyle(dragEl, "visibility", "visible"); 
3405      },
3406  
3407      /**
3408       * The proxy is automatically resized to the dimensions of the linked
3409       * element when a drag is initiated, unless resizeFrame is set to false
3410       * @method _resizeProxy
3411       * @private
3412       */
3413      _resizeProxy: function() {
3414          if (this.resizeFrame) {
3415              var DOM    = YAHOO.util.Dom;
3416              var el     = this.getEl();
3417              var dragEl = this.getDragEl();
3418  
3419              var bt = parseInt( DOM.getStyle(dragEl, "borderTopWidth"    ), 10);
3420              var br = parseInt( DOM.getStyle(dragEl, "borderRightWidth"  ), 10);
3421              var bb = parseInt( DOM.getStyle(dragEl, "borderBottomWidth" ), 10);
3422              var bl = parseInt( DOM.getStyle(dragEl, "borderLeftWidth"   ), 10);
3423  
3424              if (isNaN(bt)) { bt = 0; }
3425              if (isNaN(br)) { br = 0; }
3426              if (isNaN(bb)) { bb = 0; }
3427              if (isNaN(bl)) { bl = 0; }
3428  
3429  
3430              var newWidth  = Math.max(0, el.offsetWidth  - br - bl);                                                                                           
3431              var newHeight = Math.max(0, el.offsetHeight - bt - bb);
3432  
3433  
3434              DOM.setStyle( dragEl, "width",  newWidth  + "px" );
3435              DOM.setStyle( dragEl, "height", newHeight + "px" );
3436          }
3437      },
3438  
3439      // overrides YAHOO.util.DragDrop
3440      b4MouseDown: function(e) {
3441          this.setStartPosition();
3442          var x = YAHOO.util.Event.getPageX(e);
3443          var y = YAHOO.util.Event.getPageY(e);
3444          this.autoOffset(x, y);
3445  
3446          // This causes the autoscroll code to kick off, which means autoscroll can
3447          // happen prior to the check for a valid drag handle.
3448          // this.setDragElPos(x, y);
3449      },
3450  
3451      // overrides YAHOO.util.DragDrop
3452      b4StartDrag: function(x, y) {
3453          // show the drag frame
3454          this.showFrame(x, y);
3455      },
3456  
3457      // overrides YAHOO.util.DragDrop
3458      b4EndDrag: function(e) {
3459          YAHOO.util.Dom.setStyle(this.getDragEl(), "visibility", "hidden"); 
3460      },
3461  
3462      // overrides YAHOO.util.DragDrop
3463      // By default we try to move the element to the last location of the frame.  
3464      // This is so that the default behavior mirrors that of YAHOO.util.DD.  
3465      endDrag: function(e) {
3466          var DOM = YAHOO.util.Dom;
3467          var lel = this.getEl();
3468          var del = this.getDragEl();
3469  
3470          // Show the drag frame briefly so we can get its position
3471          // del.style.visibility = "";
3472          DOM.setStyle(del, "visibility", ""); 
3473  
3474          // Hide the linked element before the move to get around a Safari 
3475          // rendering bug.
3476          //lel.style.visibility = "hidden";
3477          DOM.setStyle(lel, "visibility", "hidden"); 
3478          YAHOO.util.DDM.moveToEl(lel, del);
3479          //del.style.visibility = "hidden";
3480          DOM.setStyle(del, "visibility", "hidden"); 
3481          //lel.style.visibility = "";
3482          DOM.setStyle(lel, "visibility", ""); 
3483      },
3484  
3485      toString: function() {
3486          return ("DDProxy " + this.id);
3487      }
3488  /**
3489  * @event mouseDownEvent
3490  * @description Provides access to the mousedown event. The mousedown does not always result in a drag operation.
3491  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3492  */
3493  
3494  /**
3495  * @event b4MouseDownEvent
3496  * @description Provides access to the mousedown event, before the mouseDownEvent gets fired. Returning false will cancel the drag.
3497  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3498  */
3499  
3500  /**
3501  * @event mouseUpEvent
3502  * @description Fired from inside DragDropMgr when the drag operation is finished.
3503  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3504  */
3505  
3506  /**
3507  * @event b4StartDragEvent
3508  * @description Fires before the startDragEvent, returning false will cancel the startDrag Event.
3509  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3510  */
3511  
3512  /**
3513  * @event startDragEvent
3514  * @description Occurs after a mouse down and the drag threshold has been met. The drag threshold default is either 3 pixels of mouse movement or 1 full second of holding the mousedown. 
3515  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3516  */
3517  
3518  /**
3519  * @event b4EndDragEvent
3520  * @description Fires before the endDragEvent. Returning false will cancel.
3521  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3522  */
3523  
3524  /**
3525  * @event endDragEvent
3526  * @description Fires on the mouseup event after a drag has been initiated (startDrag fired).
3527  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3528  */
3529  
3530  /**
3531  * @event dragEvent
3532  * @description Occurs every mousemove event while dragging.
3533  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3534  */
3535  /**
3536  * @event b4DragEvent
3537  * @description Fires before the dragEvent.
3538  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3539  */
3540  /**
3541  * @event invalidDropEvent
3542  * @description Fires when the dragged objects is dropped in a location that contains no drop targets.
3543  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3544  */
3545  /**
3546  * @event b4DragOutEvent
3547  * @description Fires before the dragOutEvent
3548  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3549  */
3550  /**
3551  * @event dragOutEvent
3552  * @description Fires when a dragged object is no longer over an object that had the onDragEnter fire. 
3553  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3554  */
3555  /**
3556  * @event dragEnterEvent
3557  * @description Occurs when the dragged object first interacts with another targettable drag and drop object.
3558  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3559  */
3560  /**
3561  * @event b4DragOverEvent
3562  * @description Fires before the dragOverEvent.
3563  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3564  */
3565  /**
3566  * @event dragOverEvent
3567  * @description Fires every mousemove event while over a drag and drop object.
3568  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3569  */
3570  /**
3571  * @event b4DragDropEvent 
3572  * @description Fires before the dragDropEvent
3573  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3574  */
3575  /**
3576  * @event dragDropEvent
3577  * @description Fires when the dragged objects is dropped on another.
3578  * @type YAHOO.util.CustomEvent See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
3579  */
3580  
3581  });
3582  /**
3583   * A DragDrop implementation that does not move, but can be a drop 
3584   * target.  You would get the same result by simply omitting implementation 
3585   * for the event callbacks, but this way we reduce the processing cost of the 
3586   * event listener and the callbacks.
3587   * @class DDTarget
3588   * @extends YAHOO.util.DragDrop 
3589   * @constructor
3590   * @param {String} id the id of the element that is a drop target
3591   * @param {String} sGroup the group of related DragDrop objects
3592   * @param {object} config an object containing configurable attributes
3593   *                 Valid properties for DDTarget in addition to those in 
3594   *                 DragDrop: 
3595   *                    none
3596   */
3597  YAHOO.util.DDTarget = function(id, sGroup, config) {
3598      if (id) {
3599          this.initTarget(id, sGroup, config);
3600      }
3601  };
3602  
3603  // YAHOO.util.DDTarget.prototype = new YAHOO.util.DragDrop();
3604  YAHOO.extend(YAHOO.util.DDTarget, YAHOO.util.DragDrop, {
3605      toString: function() {
3606          return ("DDTarget " + this.id);
3607      }
3608  });
3609  YAHOO.register("dragdrop", YAHOO.util.DragDropMgr, {version: "2.9.0", build: "2800"});
3610  
3611  }, '2.9.0' ,{"requires": ["yui2-yahoo", "yui2-dom", "yui2-event"]});


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1