Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

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