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