Subversion Repositories eFlore/Applications.cel

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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