Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

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