]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - jssource/src_files/include/javascript/yui3/build/dd/dd-ddm-drop.js
Release 6.2.0beta4
[Github/sugarcrm.git] / jssource / src_files / include / javascript / yui3 / build / dd / dd-ddm-drop.js
1 /*
2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
5 version: 3.0.0
6 build: 1549
7 */
8 YUI.add('dd-ddm-drop', function(Y) {
9
10
11     /**
12      * Extends the dd-ddm Class to add support for the placement of Drop Target shims inside the viewport shim. It also handles all Drop Target related events and interactions.
13      * @module dd
14      * @submodule dd-ddm-drop
15      * @for DDM
16      * @namespace DD
17      */
18
19     //TODO CSS class name for the bestMatch..
20     Y.mix(Y.DD.DDM, {
21         /**
22         * @private
23         * @property _noShim
24         * @description This flag turns off the use of the mouseover/mouseout shim. It should not be used unless you know what you are doing.
25         * @type {Boolean}
26         */
27         _noShim: false,
28         /**
29         * @private
30         * @property _activeShims
31         * @description Placeholder for all active shims on the page
32         * @type {Array}
33         */
34         _activeShims: [],
35         /**
36         * @private
37         * @method _hasActiveShim
38         * @description This method checks the _activeShims Object to see if there is a shim active.
39         * @return {Boolean}
40         */
41         _hasActiveShim: function() {
42             if (this._noShim) {
43                 return true;
44             }
45             return this._activeShims.length;
46         },
47         /**
48         * @private
49         * @method _addActiveShim 
50         * @description Adds a Drop Target to the list of active shims
51         * @param {Object} d The Drop instance to add to the list.
52         */
53         _addActiveShim: function(d) {
54             this._activeShims[this._activeShims.length] = d;
55         },
56         /**
57         * @private
58         * @method _removeActiveShim 
59         * @description Removes a Drop Target to the list of active shims
60         * @param {Object} d The Drop instance to remove from the list.
61         */
62         _removeActiveShim: function(d) {
63             var s = [];
64             Y.each(this._activeShims, function(v, k) {
65                 if (v._yuid !== d._yuid) {
66                     s[s.length] = v;
67                 }
68                 
69             });
70             this._activeShims = s;
71         },
72         /**
73         * @method syncActiveShims
74         * @description This method will sync the position of the shims on the Drop Targets that are currently active.
75         * @param {Boolean} force Resize/sync all Targets.
76         */
77         syncActiveShims: function(force) {
78             Y.later(0, this, function(force) {
79                 var drops = ((force) ? this.targets : this._lookup());
80                 Y.each(drops, function(v, k) {
81                     v.sizeShim.call(v);
82                 }, this);
83             }, force);
84         },
85         /**
86         * @private
87         * @property mode
88         * @description The mode that the drag operations will run in 0 for Point, 1 for Intersect, 2 for Strict
89         * @type Number
90         */
91         mode: 0,
92         /**
93         * @private
94         * @property POINT
95         * @description In point mode, a Drop is targeted by the cursor being over the Target
96         * @type Number
97         */
98         POINT: 0,
99         /**
100         * @private
101         * @property INTERSECT
102         * @description In intersect mode, a Drop is targeted by "part" of the drag node being over the Target
103         * @type Number
104         */
105         INTERSECT: 1,
106         /**
107         * @private
108         * @property STRICT
109         * @description In strict mode, a Drop is targeted by the "entire" drag node being over the Target
110         * @type Number
111         */
112         STRICT: 2,
113         /**
114         * @property useHash
115         * @description Should we only check targets that are in the viewport on drags (for performance), default: true
116         * @type {Boolean}
117         */
118         useHash: true,
119         /**
120         * @property activeDrop
121         * @description A reference to the active Drop Target
122         * @type {Object}
123         */
124         activeDrop: null,
125         /**
126         * @property validDrops
127         * @description An array of the valid Drop Targets for this interaction.
128         * @type {Array}
129         */
130         //TODO Change array/object literals to be in sync..
131         validDrops: [],
132         /**
133         * @property otherDrops
134         * @description An object literal of Other Drop Targets that we encountered during this interaction (in the case of overlapping Drop Targets)
135         * @type {Object}
136         */
137         otherDrops: {},
138         /**
139         * @property targets
140         * @description All of the Targets
141         * @type {Array}
142         */
143         targets: [],
144         /**
145         * @private 
146         * @method _addValid
147         * @description Add a Drop Target to the list of Valid Targets. This list get's regenerated on each new drag operation.
148         * @param {Object} drop
149         * @return {Self}
150         * @chainable
151         */
152         _addValid: function(drop) {
153             this.validDrops[this.validDrops.length] = drop;
154             return this;
155         },
156         /**
157         * @private 
158         * @method _removeValid
159         * @description Removes a Drop Target from the list of Valid Targets. This list get's regenerated on each new drag operation.
160         * @param {Object} drop
161         * @return {Self}
162         * @chainable
163         */
164         _removeValid: function(drop) {
165             var drops = [];
166             Y.each(this.validDrops, function(v, k) {
167                 if (v !== drop) {
168                     drops[drops.length] = v;
169                 }
170             });
171
172             this.validDrops = drops;
173             return this;
174         },
175         /**
176         * @method isOverTarget
177         * @description Check to see if the Drag element is over the target, method varies on current mode
178         * @param {Object} drop The drop to check against
179         * @return {Boolean}
180         */
181         isOverTarget: function(drop) {
182             if (this.activeDrag && drop) {
183                 var xy = this.activeDrag.mouseXY, r, dMode = this.activeDrag.get('dragMode'),
184                     aRegion;
185                 if (xy && this.activeDrag) {
186                     aRegion = this.activeDrag.region;
187                     if (dMode == this.STRICT) {
188                         return this.activeDrag.get('dragNode').inRegion(drop.region, true, aRegion);
189                     } else {
190                         if (drop && drop.shim) {
191                             if ((dMode == this.INTERSECT) && this._noShim) {
192                                 r = ((aRegion) ? aRegion : this.activeDrag.get('node'));
193                                 return drop.get('node').intersect(r).inRegion;
194                             } else {
195                                 return drop.shim.intersect({
196                                     top: xy[1],
197                                     bottom: xy[1],
198                                     left: xy[0], 
199                                     right: xy[0]
200                                 }, drop.region).inRegion;
201                             }
202                         } else {
203                             return false;
204                         }
205                     }
206                 } else {
207                     return false;
208                 }
209             } else {
210                 return false;
211             }
212         },
213         /**
214         * @method clearCache
215         * @description Clears the cache data used for this interaction.
216         */
217         clearCache: function() {
218             this.validDrops = [];
219             this.otherDrops = {};
220             this._activeShims = [];
221         },
222         /**
223         * @private
224         * @method _activateTargets
225         * @description Clear the cache and activate the shims of all the targets
226         */
227         _activateTargets: function() {
228             this.clearCache();
229             Y.each(this.targets, function(v, k) {
230                 v._activateShim.apply(v, []);
231             }, this);
232             this._handleTargetOver();
233             
234         },
235         /**
236         * @method getBestMatch
237         * @description This method will gather the area for all potential targets and see which has the hightest covered area and return it.
238         * @param {Array} drops An Array of drops to scan for the best match.
239         * @param {Boolean} all If present, it returns an Array. First item is best match, second is an Array of the other items in the original Array.
240         * @return {Object or Array} 
241         */
242         getBestMatch: function(drops, all) {
243             var biggest = null, area = 0, out;
244             
245             Y.each(drops, function(v, k) {
246                 var inter = this.activeDrag.get('dragNode').intersect(v.get('node'));
247                 v.region.area = inter.area;
248
249                 if (inter.inRegion) {
250                     if (inter.area > area) {
251                         area = inter.area;
252                         biggest = v;
253                     }
254                 }
255             }, this);
256             if (all) {
257                 out = [];
258                 //TODO Sort the others in numeric order by area covered..
259                 Y.each(drops, function(v, k) {
260                     if (v !== biggest) {
261                         out[out.length] = v;
262                     }
263                 }, this);
264                 return [biggest, out];
265             } else {
266                 return biggest;
267             }
268         },
269         /**
270         * @private
271         * @method _deactivateTargets
272         * @description This method fires the drop:hit, drag:drophit, drag:dropmiss methods and deactivates the shims..
273         */
274         _deactivateTargets: function() {
275             var other = [], tmp,
276                 activeDrag = this.activeDrag,
277                 activeDrop = this.activeDrop;
278             
279             //TODO why is this check so hard??
280             if (activeDrag && activeDrop && this.otherDrops[activeDrop]) {
281                 if (!activeDrag.get('dragMode')) {
282                     //TODO otherDrops -- private..
283                     other = this.otherDrops;
284                     delete other[activeDrop];
285                 } else {
286                     tmp = this.getBestMatch(this.otherDrops, true);
287                     activeDrop = tmp[0];
288                     other = tmp[1];
289                 }
290                 activeDrag.get('node').removeClass(this.CSS_PREFIX + '-drag-over');
291                 if (activeDrop) {
292                     activeDrop.fire('drop:hit', { drag: activeDrag, drop: activeDrop, others: other });
293                     activeDrag.fire('drag:drophit', { drag: activeDrag,  drop: activeDrop, others: other });
294                 }
295             } else if (activeDrag) {
296                 activeDrag.get('node').removeClass(this.CSS_PREFIX + '-drag-over');
297                 activeDrag.fire('drag:dropmiss', { pageX: activeDrag.lastXY[0], pageY: activeDrag.lastXY[1] });
298             } else {
299             }
300             
301             this.activeDrop = null;
302
303             Y.each(this.targets, function(v, k) {
304                 v._deactivateShim.apply(v, []);
305             }, this);
306         },
307         /**
308         * @private
309         * @method _dropMove
310         * @description This method is called when the move method is called on the Drag Object.
311         */
312         _dropMove: function() {
313             if (this._hasActiveShim()) {
314                 this._handleTargetOver();
315             } else {
316                 Y.each(this.otherDrops, function(v, k) {
317                     v._handleOut.apply(v, []);
318                 });
319             }
320         },
321         /**
322         * @private
323         * @method _lookup
324         * @description Filters the list of Drops down to those in the viewport.
325         * @return {Array} The valid Drop Targets that are in the viewport.
326         */
327         _lookup: function() {
328             if (!this.useHash || this._noShim) {
329                 return this.validDrops;
330             }
331             var drops = [];
332             //Only scan drop shims that are in the Viewport
333             Y.each(this.validDrops, function(v, k) {
334                 if (v.shim && v.shim.inViewportRegion(false, v.region)) {
335                     drops[drops.length] = v;
336                 }
337             });
338             return drops;
339                 
340         },
341         /**
342         * @private
343         * @method _handleTargetOver
344         * @description This method execs _handleTargetOver on all valid Drop Targets
345         */
346         _handleTargetOver: function() {
347             var drops = this._lookup();
348             Y.each(drops, function(v, k) {
349                 v._handleTargetOver.call(v);
350             }, this);
351         },
352         /**
353         * @private
354         * @method _regTarget
355         * @description Add the passed in Target to the targets collection
356         * @param {Object} t The Target to add to the targets collection
357         */
358         _regTarget: function(t) {
359             this.targets[this.targets.length] = t;
360         },
361         /**
362         * @private
363         * @method _unregTarget
364         * @description Remove the passed in Target from the targets collection
365         * @param {Object} drop The Target to remove from the targets collection
366         */
367         _unregTarget: function(drop) {
368             var targets = [], vdrops;
369             Y.each(this.targets, function(v, k) {
370                 if (v != drop) {
371                     targets[targets.length] = v;
372                 }
373             }, this);
374             this.targets = targets;
375
376             vdrops = [];
377             Y.each(this.validDrops, function(v, k) {
378                 if (v !== drop) {
379                     vdrops[vdrops.length] = v;
380                 }
381             });
382
383             this.validDrops = vdrops;
384         },
385         /**
386         * @method getDrop
387         * @description Get a valid Drop instance back from a Node or a selector string, false otherwise
388         * @param {String/Object} node The Node instance or Selector string to check for a valid Drop Object
389         * @return {Object}
390         */
391         getDrop: function(node) {
392             var drop = false,
393                 n = Y.Node.get(node);
394             if (n instanceof Y.Node) {
395                 Y.each(this.targets, function(v, k) {
396                     if (n.compareTo(v.get('node'))) {
397                         drop = v;
398                     }
399                 });
400             }
401             return drop;
402         }
403     }, true);
404     
405
406
407
408
409
410
411 }, '3.0.0' ,{requires:['dd-ddm'], skinnable:false});