[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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 * 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"]});
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |