]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - jssource/src_files/include/javascript/yui3/build/dd/dd-drop.js
Release 6.5.0
[Github/sugarcrm.git] / jssource / src_files / include / javascript / yui3 / build / dd / dd-drop.js
1 /*
2 Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
5 version: 3.3.0
6 build: 3167
7 */
8 YUI.add('dd-drop', function(Y) {
9
10
11     /**
12      * Provides the ability to create a Drop Target.
13      * @module dd
14      * @submodule dd-drop
15      */     
16     /**
17      * Provides the ability to create a Drop Target.
18      * @class Drop
19      * @extends Base
20      * @constructor
21      * @namespace DD
22      */
23
24     var NODE = 'node',
25         DDM = Y.DD.DDM,
26         OFFSET_HEIGHT = 'offsetHeight',
27         OFFSET_WIDTH = 'offsetWidth',
28         /**
29         * @event drop:over
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:
32         * <dl>
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>
35         * </dl>        
36         * @bubbles DDM
37         * @type {Event.Custom}
38         */
39         EV_DROP_OVER = 'drop:over',
40         /**
41         * @event drop:enter
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:
44         * <dl>
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>
47         * </dl>        
48         * @bubbles DDM
49         * @type {Event.Custom}
50         */
51         EV_DROP_ENTER = 'drop:enter',
52         /**
53         * @event drop:exit
54         * @description Fires when a drag element exits this target.
55         * @param {Event.Facade} event An Event Facade object
56         * @bubbles DDM
57         * @type {Event.Custom}
58         */
59         EV_DROP_EXIT = 'drop:exit',
60
61         /**
62         * @event drop:hit
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:
65         * <dl>
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>
69         * </dl>        
70         * @bubbles DDM
71         * @type {Event.Custom}
72         */
73         
74
75     Drop = function() {
76         this._lazyAddAttrs = false;
77         Drop.superclass.constructor.apply(this, arguments);
78
79
80         //DD init speed up.
81         Y.on('domready', Y.bind(function() {
82             Y.later(100, this, this._createShim);
83         }, this));
84         DDM._regTarget(this);
85
86         /* TODO
87         if (Dom.getStyle(this.el, 'position') == 'fixed') {
88             Event.on(window, 'scroll', function() {
89                 this.activateShim();
90             }, this, true);
91         }
92         */
93     };
94
95     Drop.NAME = 'drop';
96
97     Drop.ATTRS = {
98         /**
99         * @attribute node
100         * @description Y.Node instanace to use as the element to make a Drop Target
101         * @type Node
102         */        
103         node: {
104             setter: function(node) {
105                 var n = Y.one(node);
106                 if (!n) {
107                     Y.error('DD.Drop: Invalid Node Given: ' + node);
108                 }
109                 return n;               
110             }
111         },
112         /**
113         * @attribute groups
114         * @description Array of groups to add this drop into.
115         * @type Array
116         */        
117         groups: {
118             value: ['default'],
119             setter: function(g) {
120                 this._groups = {};
121                 Y.each(g, function(v, k) {
122                     this._groups[v] = true;
123                 }, this);
124                 return g;
125             }
126         },   
127         /**
128         * @attribute padding
129         * @description CSS style padding to make the Drop Target bigger than the node.
130         * @type String
131         */
132         padding: {
133             value: '0',
134             setter: function(p) {
135                 return DDM.cssSizestoObject(p);
136             }
137         },
138         /**
139         * @attribute lock
140         * @description Set to lock this drop element.
141         * @type Boolean
142         */        
143         lock: {
144             value: false,
145             setter: function(lock) {
146                 if (lock) {
147                     this.get(NODE).addClass(DDM.CSS_PREFIX + '-drop-locked');
148                 } else {
149                     this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-locked');
150                 }
151                 return lock;
152             }
153         },
154         /**
155         * @deprecated
156         * @attribute bubbles
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.
158         * @type Object
159         */
160         bubbles: {
161             setter: function(t) {
162                 this.addTarget(t);
163                 return t;
164             }
165         },
166         /**
167         * @deprecated
168         * @attribute useShim
169         * @description Use the Drop shim. Default: true
170         * @type Boolean
171         */
172         useShim: {
173             value: true,
174             setter: function(v) {
175                 Y.DD.DDM._noShim = !v;
176                 return v;
177             }
178         }
179     };
180
181     Y.extend(Drop, Y.Base, {
182         /**
183         * @private
184         * @property _bubbleTargets
185         * @description The default bubbleTarget for this object. Default: Y.DD.DDM
186         */
187         _bubbleTargets: Y.DD.DDM,
188         /**
189         * @method addToGroup
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.
192         * @return {Self}
193         * @chainable
194         */
195         addToGroup: function(g) {
196             this._groups[g] = true;
197             return this;
198         },
199         /**
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.
203         * @return {Self}
204         * @chainable
205         */
206         removeFromGroup: function(g) {
207             delete this._groups[g];
208             return this;
209         },
210         /**
211         * @private
212         * @method _createEvents
213         * @description This method creates all the events for this Event Target and publishes them so we get Event Bubbling.
214         */
215         _createEvents: function() {
216             
217             var ev = [
218                 EV_DROP_OVER,
219                 EV_DROP_ENTER,
220                 EV_DROP_EXIT,
221                 'drop:hit'
222             ];
223
224             Y.each(ev, function(v, k) {
225                 this.publish(v, {
226                     type: v,
227                     emitFacade: true,
228                     preventable: false,
229                     bubbles: true,
230                     queuable: false,
231                     prefix: 'drop'
232                 });
233             }, this);
234         },
235         /**
236         * @private
237         * @property _valid
238         * @description Flag for determining if the target is valid in this operation.
239         * @type Boolean
240         */
241         _valid: null,
242         /**
243         * @private
244         * @property _groups
245         * @description The groups this target belongs to.
246         * @type Array
247         */
248         _groups: null,
249         /**
250         * @property shim
251         * @description Node reference to the targets shim
252         * @type {Object}
253         */
254         shim: null,
255         /**
256         * @property region
257         * @description A region object associated with this target, used for checking regions while dragging.
258         * @type Object
259         */
260         region: null,
261         /**
262         * @property overTarget
263         * @description This flag is tripped when a drag element is over this target.
264         * @type Boolean
265         */
266         overTarget: null,
267         /**
268         * @method inGroup
269         * @description Check if this target is in one of the supplied groups.
270         * @param {Array} groups The groups to check against
271         * @return Boolean
272         */
273         inGroup: function(groups) {
274             this._valid = false;
275             var ret = false;
276             Y.each(groups, function(v, k) {
277                 if (this._groups[v]) {
278                     ret = true;
279                     this._valid = true;
280                 }
281             }, this);
282             return ret;
283         },
284         /**
285         * @private
286         * @method initializer
287         * @description Private lifecycle method
288         */
289         initializer: function(cfg) {
290             Y.later(100, this, this._createEvents);
291
292             var node = this.get(NODE), id;
293             if (!node.get('id')) {
294                 id = Y.stamp(node);
295                 node.set('id', id);
296             }
297             node.addClass(DDM.CSS_PREFIX + '-drop');
298             //Shouldn't have to do this..
299             this.set('groups', this.get('groups'));           
300         },
301         /**
302         * @private
303         * @method destructor
304         * @description Lifecycle destructor, unreg the drag from the DDM and remove listeners
305         */
306         destructor: function() {
307             DDM._unregTarget(this);
308             if (this.shim && (this.shim !== this.get(NODE))) {
309                 this.shim.detachAll();
310                 this.shim.remove();
311                 this.shim = null;
312             }
313             this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop');
314             this.detachAll();
315         },
316         /**
317         * @private
318         * @method _deactivateShim
319         * @description Removes classes from the target, resets some flags and sets the shims deactive position [-999, -999]
320         */
321         _deactivateShim: function() {
322             if (!this.shim) {
323                 return false;
324             }
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');
328
329             if (this.get('useShim')) {
330                 this.shim.setStyles({
331                     top: '-999px',
332                     left: '-999px',
333                     zIndex: '1'
334                 });
335             }
336             this.overTarget = false;
337         },
338         /**
339         * @private
340         * @method _activateShim
341         * @description Activates the shim and adds some interaction CSS classes
342         */
343         _activateShim: function() {
344             if (!DDM.activeDrag) {
345                 return false; //Nothing is dragging, no reason to activate.
346             }
347             if (this.get(NODE) === DDM.activeDrag.get(NODE)) {
348                 return false;
349             }
350             if (this.get('lock')) {
351                 return false;
352             }
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');
359                 DDM._addValid(this);
360                 this.overTarget = false;
361                 if (!this.get('useShim')) {
362                     this.shim = this.get(NODE);
363                 }
364                 this.sizeShim();
365             } else {
366                 DDM._removeValid(this);
367                 node.removeClass(DDM.CSS_PREFIX + '-drop-active-valid');
368                 node.addClass(DDM.CSS_PREFIX + '-drop-active-invalid');
369             }
370         },
371         /**
372         * @method sizeShim
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..
374         */
375         sizeShim: function() {
376             if (!DDM.activeDrag) {
377                 return false; //Nothing is dragging, no reason to activate.
378             }
379             if (this.get(NODE) === DDM.activeDrag.get(NODE)) {
380                 return false;
381             }
382             //if (this.get('lock') || !this.get('useShim')) {
383             if (this.get('lock')) {
384                 return false;
385             }
386             if (!this.shim) {
387                 Y.later(100, this, this.sizeShim);
388                 return false;
389             }
390             var node = this.get(NODE),
391                 nh = node.get(OFFSET_HEIGHT),
392                 nw = node.get(OFFSET_WIDTH),
393                 xy = node.getXY(),
394                 p = this.get('padding'),
395                 dd, dH, dW;
396
397
398             //Apply 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;
403             
404
405             if (DDM.activeDrag.get('dragMode') === DDM.INTERSECT) {
406                 //Intersect Mode, make the shim bigger
407                 dd = DDM.activeDrag;
408                 dH = dd.get(NODE).get(OFFSET_HEIGHT);
409                 dW = dd.get(NODE).get(OFFSET_WIDTH);
410                 
411                 nh = (nh + dH);
412                 nw = (nw + dW);
413                 xy[0] = xy[0] - (dW - dd.deltaXY[0]);
414                 xy[1] = xy[1] - (dH - dd.deltaXY[1]);
415
416             }
417             
418             if (this.get('useShim')) {
419                 //Set the style on the shim
420                 this.shim.setStyles({
421                     height: nh + 'px',
422                     width: nw + 'px',
423                     top: xy[1] + 'px',
424                     left: xy[0] + 'px'
425                 });
426             }
427
428             //Create the region to be used by intersect when a drag node is over us.
429             this.region = {
430                 '0': xy[0], 
431                 '1': xy[1],
432                 area: 0,
433                 top: xy[1],
434                 right: xy[0] + nw,
435                 bottom: xy[1] + nh,
436                 left: xy[0]
437             };
438         },
439         /**
440         * @private
441         * @method _createShim
442         * @description Creates the Target shim and adds it to the DDM's playground..
443         */
444         _createShim: function() {
445             //No playground, defer
446             if (!DDM._pg) {
447                 Y.later(10, this, this._createShim);
448                 return;
449             }
450             //Shim already here, cancel
451             if (this.shim) {
452                 return;
453             }
454             var s = this.get('node');
455
456             if (this.get('useShim')) {
457                 s = Y.Node.create('<div id="' + this.get(NODE).get('id') + '_shim"></div>');
458                 s.setStyles({
459                     height: this.get(NODE).get(OFFSET_HEIGHT) + 'px',
460                     width: this.get(NODE).get(OFFSET_WIDTH) + 'px',
461                     backgroundColor: 'yellow',
462                     opacity: '.5',
463                     zIndex: '1',
464                     overflow: 'hidden',
465                     top: '-900px',
466                     left: '-900px',
467                     position:  'absolute'
468                 });
469
470                 DDM._pg.appendChild(s);
471
472                 s.on('mouseover', Y.bind(this._handleOverEvent, this));
473                 s.on('mouseout', Y.bind(this._handleOutEvent, this));
474             }
475
476
477             this.shim = s;
478         },
479         /**
480         * @private
481         * @method _handleOverTarget
482         * @description This handles the over target call made from this object or from the DDM
483         */
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 });
492                 } else {
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();
501                     }
502                 }
503             } else {
504                 this._handleOut();
505             }
506         },
507         /**
508         * @private
509         * @method _handleOverEvent
510         * @description Handles the mouseover DOM event on the Target Shim
511         */
512         _handleOverEvent: function() {
513             this.shim.setStyle('zIndex', '999');
514             DDM._addActiveShim(this);
515         },
516         /**
517         * @private
518         * @method _handleOutEvent
519         * @description Handles the mouseout DOM event on the Target Shim
520         */
521         _handleOutEvent: function() {
522             this.shim.setStyle('zIndex', '1');
523             DDM._removeActiveShim(this);
524         },
525         /**
526         * @private
527         * @method _handleOut
528         * @description Handles out of target calls/checks
529         */
530         _handleOut: function(force) {
531             if (!DDM.isOverTarget(this) || force) {
532                 if (this.overTarget) {
533                     this.overTarget = false;
534                     if (!force) {
535                         DDM._removeActiveShim(this);
536                     }
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];
543                     }
544                 }
545             }
546         }
547     });
548
549     Y.DD.Drop = Drop;
550
551
552
553
554
555 }, '3.3.0' ,{requires:['dd-ddm-drop', 'dd-drag'], skinnable:false});