adhearsion 0.7.6 → 0.7.7

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