2 Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
8 YUI.add('dd-drop', function(Y) {
12 * Provides the ability to create a Drop Target.
17 * Provides the ability to create a Drop Target.
26 OFFSET_HEIGHT = 'offsetHeight',
27 OFFSET_WIDTH = 'offsetWidth',
30 * @description Fires when a drag element is over this target.
31 * @param {Event.Facade} event An Event Facade object with the following specific property added:
33 * <dt>drop</dt><dd>The drop object at the time of the event.</dd>
34 * <dt>drag</dt><dd>The drag object at the time of the event.</dd>
37 * @type {Event.Custom}
39 EV_DROP_OVER = 'drop:over',
42 * @description Fires when a drag element enters this target.
43 * @param {Event.Facade} event An Event Facade object with the following specific property added:
45 * <dt>drop</dt><dd>The drop object at the time of the event.</dd>
46 * <dt>drag</dt><dd>The drag object at the time of the event.</dd>
49 * @type {Event.Custom}
51 EV_DROP_ENTER = 'drop:enter',
54 * @description Fires when a drag element exits this target.
55 * @param {Event.Facade} event An Event Facade object
57 * @type {Event.Custom}
59 EV_DROP_EXIT = 'drop:exit',
63 * @description Fires when a draggable node is dropped on this Drop Target. (Fired from dd-ddm-drop)
64 * @param {Event.Facade} event An Event Facade object with the following specific property added:
66 * <dt>drop</dt><dd>The best guess on what was dropped on.</dd>
67 * <dt>drag</dt><dd>The drag object at the time of the event.</dd>
68 * <dt>others</dt><dd>An array of all the other drop targets that was dropped on.</dd>
71 * @type {Event.Custom}
76 this._lazyAddAttrs = false;
77 Drop.superclass.constructor.apply(this, arguments);
81 Y.on('domready', Y.bind(function() {
82 Y.later(100, this, this._createShim);
87 if (Dom.getStyle(this.el, 'position') == 'fixed') {
88 Event.on(window, 'scroll', function() {
100 * @description Y.Node instanace to use as the element to make a Drop Target
104 setter: function(node) {
107 Y.error('DD.Drop: Invalid Node Given: ' + node);
114 * @description Array of groups to add this drop into.
119 setter: function(g) {
121 Y.each(g, function(v, k) {
122 this._groups[v] = true;
129 * @description CSS style padding to make the Drop Target bigger than the node.
134 setter: function(p) {
135 return DDM.cssSizestoObject(p);
140 * @description Set to lock this drop element.
145 setter: function(lock) {
147 this.get(NODE).addClass(DDM.CSS_PREFIX + '-drop-locked');
149 this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-locked');
157 * @description Controls the default bubble parent for this Drop instance. Default: Y.DD.DDM. Set to false to disable bubbling. Use bubbleTargets in config.
161 setter: function(t) {
169 * @description Use the Drop shim. Default: true
174 setter: function(v) {
175 Y.DD.DDM._noShim = !v;
181 Y.extend(Drop, Y.Base, {
184 * @property _bubbleTargets
185 * @description The default bubbleTarget for this object. Default: Y.DD.DDM
187 _bubbleTargets: Y.DD.DDM,
190 * @description Add this Drop instance to a group, this should be used for on-the-fly group additions.
191 * @param {String} g The group to add this Drop Instance to.
195 addToGroup: function(g) {
196 this._groups[g] = true;
200 * @method removeFromGroup
201 * @description Remove this Drop instance from a group, this should be used for on-the-fly group removals.
202 * @param {String} g The group to remove this Drop Instance from.
206 removeFromGroup: function(g) {
207 delete this._groups[g];
212 * @method _createEvents
213 * @description This method creates all the events for this Event Target and publishes them so we get Event Bubbling.
215 _createEvents: function() {
224 Y.each(ev, function(v, k) {
238 * @description Flag for determining if the target is valid in this operation.
245 * @description The groups this target belongs to.
251 * @description Node reference to the targets shim
257 * @description A region object associated with this target, used for checking regions while dragging.
262 * @property overTarget
263 * @description This flag is tripped when a drag element is over this target.
269 * @description Check if this target is in one of the supplied groups.
270 * @param {Array} groups The groups to check against
273 inGroup: function(groups) {
276 Y.each(groups, function(v, k) {
277 if (this._groups[v]) {
286 * @method initializer
287 * @description Private lifecycle method
289 initializer: function(cfg) {
290 Y.later(100, this, this._createEvents);
292 var node = this.get(NODE), id;
293 if (!node.get('id')) {
297 node.addClass(DDM.CSS_PREFIX + '-drop');
298 //Shouldn't have to do this..
299 this.set('groups', this.get('groups'));
304 * @description Lifecycle destructor, unreg the drag from the DDM and remove listeners
306 destructor: function() {
307 DDM._unregTarget(this);
308 if (this.shim && (this.shim !== this.get(NODE))) {
309 this.shim.detachAll();
313 this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop');
318 * @method _deactivateShim
319 * @description Removes classes from the target, resets some flags and sets the shims deactive position [-999, -999]
321 _deactivateShim: function() {
325 this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-active-valid');
326 this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-active-invalid');
327 this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-over');
329 if (this.get('useShim')) {
330 this.shim.setStyles({
336 this.overTarget = false;
340 * @method _activateShim
341 * @description Activates the shim and adds some interaction CSS classes
343 _activateShim: function() {
344 if (!DDM.activeDrag) {
345 return false; //Nothing is dragging, no reason to activate.
347 if (this.get(NODE) === DDM.activeDrag.get(NODE)) {
350 if (this.get('lock')) {
353 var node = this.get(NODE);
354 //TODO Visibility Check..
355 //if (this.inGroup(DDM.activeDrag.get('groups')) && this.get(NODE).isVisible()) {
356 if (this.inGroup(DDM.activeDrag.get('groups'))) {
357 node.removeClass(DDM.CSS_PREFIX + '-drop-active-invalid');
358 node.addClass(DDM.CSS_PREFIX + '-drop-active-valid');
360 this.overTarget = false;
361 if (!this.get('useShim')) {
362 this.shim = this.get(NODE);
366 DDM._removeValid(this);
367 node.removeClass(DDM.CSS_PREFIX + '-drop-active-valid');
368 node.addClass(DDM.CSS_PREFIX + '-drop-active-invalid');
373 * @description Positions and sizes the shim with the raw data from the node, this can be used to programatically adjust the Targets shim for Animation..
375 sizeShim: function() {
376 if (!DDM.activeDrag) {
377 return false; //Nothing is dragging, no reason to activate.
379 if (this.get(NODE) === DDM.activeDrag.get(NODE)) {
382 //if (this.get('lock') || !this.get('useShim')) {
383 if (this.get('lock')) {
387 Y.later(100, this, this.sizeShim);
390 var node = this.get(NODE),
391 nh = node.get(OFFSET_HEIGHT),
392 nw = node.get(OFFSET_WIDTH),
394 p = this.get('padding'),
399 nw = nw + p.left + p.right;
400 nh = nh + p.top + p.bottom;
401 xy[0] = xy[0] - p.left;
402 xy[1] = xy[1] - p.top;
405 if (DDM.activeDrag.get('dragMode') === DDM.INTERSECT) {
406 //Intersect Mode, make the shim bigger
408 dH = dd.get(NODE).get(OFFSET_HEIGHT);
409 dW = dd.get(NODE).get(OFFSET_WIDTH);
413 xy[0] = xy[0] - (dW - dd.deltaXY[0]);
414 xy[1] = xy[1] - (dH - dd.deltaXY[1]);
418 if (this.get('useShim')) {
419 //Set the style on the shim
420 this.shim.setStyles({
428 //Create the region to be used by intersect when a drag node is over us.
441 * @method _createShim
442 * @description Creates the Target shim and adds it to the DDM's playground..
444 _createShim: function() {
445 //No playground, defer
447 Y.later(10, this, this._createShim);
450 //Shim already here, cancel
454 var s = this.get('node');
456 if (this.get('useShim')) {
457 s = Y.Node.create('<div id="' + this.get(NODE).get('id') + '_shim"></div>');
459 height: this.get(NODE).get(OFFSET_HEIGHT) + 'px',
460 width: this.get(NODE).get(OFFSET_WIDTH) + 'px',
461 backgroundColor: 'yellow',
470 DDM._pg.appendChild(s);
472 s.on('mouseover', Y.bind(this._handleOverEvent, this));
473 s.on('mouseout', Y.bind(this._handleOutEvent, this));
481 * @method _handleOverTarget
482 * @description This handles the over target call made from this object or from the DDM
484 _handleTargetOver: function() {
485 if (DDM.isOverTarget(this)) {
486 this.get(NODE).addClass(DDM.CSS_PREFIX + '-drop-over');
487 DDM.activeDrop = this;
488 DDM.otherDrops[this] = this;
489 if (this.overTarget) {
490 DDM.activeDrag.fire('drag:over', { drop: this, drag: DDM.activeDrag });
491 this.fire(EV_DROP_OVER, { drop: this, drag: DDM.activeDrag });
493 //Prevent an enter before a start..
494 if (DDM.activeDrag.get('dragging')) {
495 this.overTarget = true;
496 this.fire(EV_DROP_ENTER, { drop: this, drag: DDM.activeDrag });
497 DDM.activeDrag.fire('drag:enter', { drop: this, drag: DDM.activeDrag });
498 DDM.activeDrag.get(NODE).addClass(DDM.CSS_PREFIX + '-drag-over');
499 //TODO - Is this needed??
500 //DDM._handleTargetOver();
509 * @method _handleOverEvent
510 * @description Handles the mouseover DOM event on the Target Shim
512 _handleOverEvent: function() {
513 this.shim.setStyle('zIndex', '999');
514 DDM._addActiveShim(this);
518 * @method _handleOutEvent
519 * @description Handles the mouseout DOM event on the Target Shim
521 _handleOutEvent: function() {
522 this.shim.setStyle('zIndex', '1');
523 DDM._removeActiveShim(this);
528 * @description Handles out of target calls/checks
530 _handleOut: function(force) {
531 if (!DDM.isOverTarget(this) || force) {
532 if (this.overTarget) {
533 this.overTarget = false;
535 DDM._removeActiveShim(this);
537 if (DDM.activeDrag) {
538 this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-over');
539 DDM.activeDrag.get(NODE).removeClass(DDM.CSS_PREFIX + '-drag-over');
540 this.fire(EV_DROP_EXIT);
541 DDM.activeDrag.fire('drag:exit', { drop: this });
542 delete DDM.otherDrops[this];
555 }, '3.3.0' ,{requires:['dd-ddm-drop', 'dd-drag'], skinnable:false});