adhearsion 0.7.6 → 0.7.7

Sign up to get free protection for your applications and to get access to all the features.
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"});