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
                Y.log('bubbles is deprecated use bubbleTargets: HOST', 'warn', 'dd');
162
                this.addTarget(t);
163
                return t;
164
            }
165
        },
166
        /**
167
        * Use the Drop shim. Default: true
168
        * @deprecated
169
        * @attribute useShim
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
        * The default bubbleTarget for this object. Default: Y.DD.DDM
184
        * @private
185
        * @property _bubbleTargets
186
        */
187
        _bubbleTargets: Y.DD.DDM,
188
        /**
189
        * Add this Drop instance to a group, this should be used for on-the-fly group additions.
190
        * @method addToGroup
191
        * @param {String} g The group to add this Drop Instance to.
192
        * @chainable
193
        */
194
        addToGroup: function(g) {
195
            this._groups[g] = true;
196
            return this;
197
        },
198
        /**
199
        * Remove this Drop instance from a group, this should be used for on-the-fly group removals.
200
        * @method removeFromGroup
201
        * @param {String} g The group to remove this Drop Instance from.
202
        * @chainable
203
        */
204
        removeFromGroup: function(g) {
205
            delete this._groups[g];
206
            return this;
207
        },
208
        /**
209
        * This method creates all the events for this Event Target and publishes them so we get Event Bubbling.
210
        * @private
211
        * @method _createEvents
212
        */
213
        _createEvents: function() {
214
 
215
            var ev = [
216
                EV_DROP_OVER,
217
                EV_DROP_ENTER,
218
                EV_DROP_EXIT,
219
                'drop:hit'
220
            ];
221
 
222
            Y.Array.each(ev, function(v) {
223
                this.publish(v, {
224
                    type: v,
225
                    emitFacade: true,
226
                    preventable: false,
227
                    bubbles: true,
228
                    queuable: false,
229
                    prefix: 'drop'
230
                });
231
            }, this);
232
        },
233
        /**
234
        * Flag for determining if the target is valid in this operation.
235
        * @private
236
        * @property _valid
237
        * @type Boolean
238
        */
239
        _valid: null,
240
        /**
241
        * The groups this target belongs to.
242
        * @private
243
        * @property _groups
244
        * @type Array
245
        */
246
        _groups: null,
247
        /**
248
        * Node reference to the targets shim
249
        * @property shim
250
        * @type {Object}
251
        */
252
        shim: null,
253
        /**
254
        * A region object associated with this target, used for checking regions while dragging.
255
        * @property region
256
        * @type Object
257
        */
258
        region: null,
259
        /**
260
        * This flag is tripped when a drag element is over this target.
261
        * @property overTarget
262
        * @type Boolean
263
        */
264
        overTarget: null,
265
        /**
266
        * Check if this target is in one of the supplied groups.
267
        * @method inGroup
268
        * @param {Array} groups The groups to check against
269
        * @return Boolean
270
        */
271
        inGroup: function(groups) {
272
            this._valid = false;
273
            var ret = false;
274
            Y.Array.each(groups, function(v) {
275
                if (this._groups[v]) {
276
                    ret = true;
277
                    this._valid = true;
278
                }
279
            }, this);
280
            return ret;
281
        },
282
        /**
283
        * Private lifecycle method
284
        * @private
285
        * @method initializer
286
        */
287
        initializer: function() {
288
            Y.later(100, this, this._createEvents);
289
 
290
            var node = this.get(NODE), id;
291
            if (!node.get('id')) {
292
                id = Y.stamp(node);
293
                node.set('id', id);
294
            }
295
            node.addClass(DDM.CSS_PREFIX + '-drop');
296
            //Shouldn't have to do this..
297
            this.set('groups', this.get('groups'));
298
        },
299
        /**
300
        * Lifecycle destructor, unreg the drag from the DDM and remove listeners
301
        * @private
302
        * @method destructor
303
        */
304
        destructor: function() {
305
            DDM._unregTarget(this);
306
            if (this.shim && (this.shim !== this.get(NODE))) {
307
                this.shim.detachAll();
308
                this.shim.remove();
309
                this.shim = null;
310
            }
311
            this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop');
312
            this.detachAll();
313
        },
314
        /**
315
        * Removes classes from the target, resets some flags and sets the shims deactive position [-999, -999]
316
        * @private
317
        * @method _deactivateShim
318
        */
319
        _deactivateShim: function() {
320
            if (!this.shim) {
321
                return false;
322
            }
323
            this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-active-valid');
324
            this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-active-invalid');
325
            this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-over');
326
 
327
            if (this.get('useShim')) {
328
                this.shim.setStyles({
329
                    top: '-999px',
330
                    left: '-999px',
331
                    zIndex: '1'
332
                });
333
            }
334
            this.overTarget = false;
335
        },
336
        /**
337
        * Activates the shim and adds some interaction CSS classes
338
        * @private
339
        * @method _activateShim
340
        */
341
        _activateShim: function() {
342
            if (!DDM.activeDrag) {
343
                return false; //Nothing is dragging, no reason to activate.
344
            }
345
            if (this.get(NODE) === DDM.activeDrag.get(NODE)) {
346
                return false;
347
            }
348
            if (this.get('lock')) {
349
                return false;
350
            }
351
            var node = this.get(NODE);
352
            //TODO Visibility Check..
353
            //if (this.inGroup(DDM.activeDrag.get('groups')) && this.get(NODE).isVisible()) {
354
            if (this.inGroup(DDM.activeDrag.get('groups'))) {
355
                node.removeClass(DDM.CSS_PREFIX + '-drop-active-invalid');
356
                node.addClass(DDM.CSS_PREFIX + '-drop-active-valid');
357
                DDM._addValid(this);
358
                this.overTarget = false;
359
                if (!this.get('useShim')) {
360
                    this.shim = this.get(NODE);
361
                }
362
                this.sizeShim();
363
            } else {
364
                DDM._removeValid(this);
365
                node.removeClass(DDM.CSS_PREFIX + '-drop-active-valid');
366
                node.addClass(DDM.CSS_PREFIX + '-drop-active-invalid');
367
            }
368
        },
369
        /**
370
        * Positions and sizes the shim with the raw data from the node,
371
        * this can be used to programatically adjust the Targets shim for Animation..
372
        * @method sizeShim
373
        */
374
        sizeShim: function() {
375
            if (!DDM.activeDrag) {
376
                return false; //Nothing is dragging, no reason to activate.
377
            }
378
            if (this.get(NODE) === DDM.activeDrag.get(NODE)) {
379
                return false;
380
            }
381
            //if (this.get('lock') || !this.get('useShim')) {
382
            if (this.get('lock')) {
383
                return false;
384
            }
385
            if (!this.shim) {
386
                Y.later(100, this, this.sizeShim);
387
                return false;
388
            }
389
            var node = this.get(NODE),
390
                nh = node.get(OFFSET_HEIGHT),
391
                nw = node.get(OFFSET_WIDTH),
392
                xy = node.getXY(),
393
                p = this.get('padding'),
394
                dd, dH, dW;
395
 
396
 
397
            //Apply padding
398
            nw = nw + p.left + p.right;
399
            nh = nh + p.top + p.bottom;
400
            xy[0] = xy[0] - p.left;
401
            xy[1] = xy[1] - p.top;
402
 
403
 
404
            if (DDM.activeDrag.get('dragMode') === DDM.INTERSECT) {
405
                //Intersect Mode, make the shim bigger
406
                dd = DDM.activeDrag;
407
                dH = dd.get(NODE).get(OFFSET_HEIGHT);
408
                dW = dd.get(NODE).get(OFFSET_WIDTH);
409
 
410
                nh = (nh + dH);
411
                nw = (nw + dW);
412
                xy[0] = xy[0] - (dW - dd.deltaXY[0]);
413
                xy[1] = xy[1] - (dH - dd.deltaXY[1]);
414
 
415
            }
416
 
417
            if (this.get('useShim')) {
418
                //Set the style on the shim
419
                this.shim.setStyles({
420
                    height: nh + 'px',
421
                    width: nw + 'px',
422
                    top: xy[1] + 'px',
423
                    left: xy[0] + 'px'
424
                });
425
            }
426
 
427
            //Create the region to be used by intersect when a drag node is over us.
428
            this.region = {
429
                '0': xy[0],
430
                '1': xy[1],
431
                area: 0,
432
                top: xy[1],
433
                right: xy[0] + nw,
434
                bottom: xy[1] + nh,
435
                left: xy[0]
436
            };
437
        },
438
        /**
439
        * Creates the Target shim and adds it to the DDM's playground..
440
        * @private
441
        * @method _createShim
442
        */
443
        _createShim: function() {
444
            //No playground, defer
445
            if (!DDM._pg) {
446
                Y.later(10, this, this._createShim);
447
                return;
448
            }
449
            //Shim already here, cancel
450
            if (this.shim) {
451
                return;
452
            }
453
            var s = this.get('node');
454
 
455
            if (this.get('useShim')) {
456
                s = Y.Node.create('<div id="' + this.get(NODE).get('id') + '_shim"></div>');
457
                s.setStyles({
458
                    height: this.get(NODE).get(OFFSET_HEIGHT) + 'px',
459
                    width: this.get(NODE).get(OFFSET_WIDTH) + 'px',
460
                    backgroundColor: 'yellow',
461
                    opacity: '.5',
462
                    zIndex: '1',
463
                    overflow: 'hidden',
464
                    top: '-900px',
465
                    left: '-900px',
466
                    position:  'absolute'
467
                });
468
 
469
                DDM._pg.appendChild(s);
470
 
471
                s.on('mouseover', Y.bind(this._handleOverEvent, this));
472
                s.on('mouseout', Y.bind(this._handleOutEvent, this));
473
            }
474
 
475
 
476
            this.shim = s;
477
        },
478
        /**
479
        * This handles the over target call made from this object or from the DDM
480
        * @private
481
        * @method _handleOverTarget
482
        */
483
        _handleTargetOver: function() {
484
            if (DDM.isOverTarget(this)) {
485
                this.get(NODE).addClass(DDM.CSS_PREFIX + '-drop-over');
486
                DDM.activeDrop = this;
487
                DDM.otherDrops[this] = this;
488
                if (this.overTarget) {
489
                    DDM.activeDrag.fire('drag:over', { drop: this, drag: DDM.activeDrag });
490
                    this.fire(EV_DROP_OVER, { drop: this, drag: DDM.activeDrag });
491
                } else {
492
                    //Prevent an enter before a start..
493
                    if (DDM.activeDrag.get('dragging')) {
494
                        this.overTarget = true;
495
                        this.fire(EV_DROP_ENTER, { drop: this, drag: DDM.activeDrag });
496
                        DDM.activeDrag.fire('drag:enter', { drop: this, drag: DDM.activeDrag });
497
                        DDM.activeDrag.get(NODE).addClass(DDM.CSS_PREFIX + '-drag-over');
498
                        //TODO - Is this needed??
499
                        //DDM._handleTargetOver();
500
                    }
501
                }
502
            } else {
503
                this._handleOut();
504
            }
505
        },
506
        /**
507
        * Handles the mouseover DOM event on the Target Shim
508
        * @private
509
        * @method _handleOverEvent
510
        */
511
        _handleOverEvent: function() {
512
            this.shim.setStyle('zIndex', '999');
513
            DDM._addActiveShim(this);
514
        },
515
        /**
516
        * Handles the mouseout DOM event on the Target Shim
517
        * @private
518
        * @method _handleOutEvent
519
        */
520
        _handleOutEvent: function() {
521
            this.shim.setStyle('zIndex', '1');
522
            DDM._removeActiveShim(this);
523
        },
524
        /**
525
        * Handles out of target calls/checks
526
        * @private
527
        * @method _handleOut
528
        */
529
        _handleOut: function(force) {
530
            if (!DDM.isOverTarget(this) || force) {
531
                if (this.overTarget) {
532
                    this.overTarget = false;
533
                    if (!force) {
534
                        DDM._removeActiveShim(this);
535
                    }
536
                    if (DDM.activeDrag) {
537
                        this.get(NODE).removeClass(DDM.CSS_PREFIX + '-drop-over');
538
                        DDM.activeDrag.get(NODE).removeClass(DDM.CSS_PREFIX + '-drag-over');
539
                        this.fire(EV_DROP_EXIT, { drop: this, drag: DDM.activeDrag });
540
                        DDM.activeDrag.fire('drag:exit', { drop: this, drag: DDM.activeDrag });
541
                        delete DDM.otherDrops[this];
542
                    }
543
                }
544
            }
545
        }
546
    });
547
 
548
    Y.DD.Drop = Drop;
549
 
550
 
551
 
552
 
553
}, '3.18.1', {"requires": ["dd-drag", "dd-ddm-drop"]});