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