Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
YUI.add('scrollview-scrollbars', function (Y, NAME) {
2
 
3
/**
4
 * Provides a plugin, which adds support for a scroll indicator to ScrollView instances
5
 *
6
 * @module scrollview
7
 * @submodule scrollview-scrollbars
8
 */
9
 
10
var getClassName = Y.ClassNameManager.getClassName,
11
    _classNames,
12
 
13
    Transition = Y.Transition,
14
    NATIVE_TRANSITIONS = Transition.useNative,
15
    SCROLLBAR = 'scrollbar',
16
    SCROLLVIEW = 'scrollview',
17
 
18
    VERTICAL_NODE = "verticalNode",
19
    HORIZONTAL_NODE = "horizontalNode",
20
 
21
    CHILD_CACHE = "childCache",
22
 
23
    TOP = "top",
24
    LEFT = "left",
25
    WIDTH = "width",
26
    HEIGHT = "height",
27
 
28
    HORIZ_CACHE = "_sbh",
29
    VERT_CACHE = "_sbv",
30
 
31
    TRANSITION_PROPERTY = Y.ScrollView._TRANSITION.PROPERTY,
32
    TRANSFORM = "transform",
33
 
34
    TRANSLATE_X = "translateX(",
35
    TRANSLATE_Y = "translateY(",
36
 
37
    SCALE_X = "scaleX(",
38
    SCALE_Y = "scaleY(",
39
 
40
    SCROLL_X = "scrollX",
41
    SCROLL_Y = "scrollY",
42
 
43
    PX = "px",
44
    CLOSE = ")",
45
    PX_CLOSE = PX + CLOSE;
46
 
47
/**
48
 * ScrollView plugin that adds scroll indicators to ScrollView instances
49
 *
50
 * @class ScrollViewScrollbars
51
 * @namespace Plugin
52
 * @extends Plugin.Base
53
 * @constructor
54
 */
55
function ScrollbarsPlugin() {
56
    ScrollbarsPlugin.superclass.constructor.apply(this, arguments);
57
}
58
 
59
ScrollbarsPlugin.CLASS_NAMES = {
60
    showing: getClassName(SCROLLVIEW, SCROLLBAR, 'showing'),
61
    scrollbar: getClassName(SCROLLVIEW, SCROLLBAR),
62
    scrollbarV: getClassName(SCROLLVIEW, SCROLLBAR, 'vert'),
63
    scrollbarH: getClassName(SCROLLVIEW, SCROLLBAR, 'horiz'),
64
    scrollbarVB: getClassName(SCROLLVIEW, SCROLLBAR, 'vert', 'basic'),
65
    scrollbarHB: getClassName(SCROLLVIEW, SCROLLBAR, 'horiz', 'basic'),
66
    child: getClassName(SCROLLVIEW, 'child'),
67
    first: getClassName(SCROLLVIEW, 'first'),
68
    middle: getClassName(SCROLLVIEW, 'middle'),
69
    last: getClassName(SCROLLVIEW, 'last')
70
};
71
 
72
_classNames = ScrollbarsPlugin.CLASS_NAMES;
73
 
74
/**
75
 * The identity of the plugin
76
 *
77
 * @property NAME
78
 * @type String
79
 * @default 'pluginScrollViewScrollbars'
80
 * @static
81
 */
82
ScrollbarsPlugin.NAME = 'pluginScrollViewScrollbars';
83
 
84
/**
85
 * The namespace on which the plugin will reside.
86
 *
87
 * @property NS
88
 * @type String
89
 * @default 'scrollbars'
90
 * @static
91
 */
92
ScrollbarsPlugin.NS = 'scrollbars';
93
 
94
/**
95
 * HTML template for the scrollbar
96
 *
97
 * @property SCROLLBAR_TEMPLATE
98
 * @type Object
99
 * @static
100
 */
101
ScrollbarsPlugin.SCROLLBAR_TEMPLATE = [
102
    '<div>',
103
    '<span class="' + _classNames.child + ' ' + _classNames.first + '"></span>',
104
    '<span class="' + _classNames.child + ' ' + _classNames.middle + '"></span>',
105
    '<span class="' + _classNames.child + ' ' + _classNames.last + '"></span>',
106
    '</div>'
107
].join('');
108
 
109
/**
110
 * The default attribute configuration for the plugin
111
 *
112
 * @property ATTRS
113
 * @type Object
114
 * @static
115
 */
116
ScrollbarsPlugin.ATTRS = {
117
 
118
    /**
119
     * Vertical scrollbar node
120
     *
121
     * @attribute verticalNode
122
     * @type Y.Node
123
     */
124
    verticalNode: {
125
        setter: '_setNode',
126
        valueFn: '_defaultNode'
127
    },
128
 
129
    /**
130
     * Horizontal scrollbar node
131
     *
132
     * @attribute horizontalNode
133
     * @type Y.Node
134
     */
135
    horizontalNode: {
136
        setter: '_setNode',
137
        valueFn: '_defaultNode'
138
    }
139
};
140
 
141
Y.namespace("Plugin").ScrollViewScrollbars = Y.extend(ScrollbarsPlugin, Y.Plugin.Base, {
142
 
143
    /**
144
     * Designated initializer
145
     *
146
     * @method initializer
147
     */
148
    initializer: function() {
149
        this._host = this.get("host");
150
 
151
        this.afterHostEvent('scrollEnd', this._hostScrollEnd);
152
        this.afterHostMethod('scrollTo', this._update);
153
        this.afterHostMethod('_uiDimensionsChange', this._hostDimensionsChange);
154
    },
155
 
156
    /**
157
     * Set up the DOM nodes for the scrollbars. This method is invoked whenever the
158
     * host's _uiDimensionsChange fires, giving us the opportunity to remove un-needed
159
     * scrollbars, as well as add one if necessary.
160
     *
161
     * @method _hostDimensionsChange
162
     * @protected
163
     */
164
    _hostDimensionsChange: function() {
165
        var host = this._host,
166
            axis = host._cAxis,
167
            scrollX = host.get(SCROLL_X),
168
            scrollY = host.get(SCROLL_Y);
169
 
170
        this._dims = host._getScrollDims();
171
 
172
        if (axis && axis.y) {
173
            this._renderBar(this.get(VERTICAL_NODE), true, 'vert');
174
        }
175
 
176
        if (axis && axis.x) {
177
            this._renderBar(this.get(HORIZONTAL_NODE), true, 'horiz');
178
        }
179
 
180
        this._update(scrollX, scrollY);
181
 
182
        Y.later(500, this, 'flash', true);
183
    },
184
 
185
    /**
186
     * Handler for the scrollEnd event fired by the host. Default implementation flashes the scrollbar
187
     *
188
     * @method _hostScrollEnd
189
     * @param {EventFacade} e The event facade.
190
     * @protected
191
     */
192
    _hostScrollEnd : function() {
193
        var host = this._host,
194
            scrollX = host.get(SCROLL_X),
195
            scrollY = host.get(SCROLL_Y);
196
 
197
        this.flash();
198
 
199
        this._update(scrollX, scrollY);
200
    },
201
 
202
    /**
203
     * Adds or removes a scrollbar node from the document.
204
     *
205
     * @method _renderBar
206
     * @private
207
     * @param {Node} bar The scrollbar node
208
     * @param {boolean} add true, to add the node, false to remove it
209
     */
210
    _renderBar: function(bar, add) {
211
        var inDoc = bar.inDoc(),
212
            bb = this._host._bb,
213
            className = bar.getData("isHoriz") ? _classNames.scrollbarHB : _classNames.scrollbarVB;
214
 
215
        if (add && !inDoc) {
216
            bb.append(bar);
217
            bar.toggleClass(className, this._basic);
218
            this._setChildCache(bar);
219
        } else if(!add && inDoc) {
220
            bar.remove();
221
            this._clearChildCache(bar);
222
        }
223
    },
224
 
225
    /**
226
     * Caches scrollbar child element information,
227
     * to optimize _update implementation
228
     *
229
     * @method _setChildCache
230
     * @private
231
     * @param {Node} node
232
     */
233
    _setChildCache : function(node) {
234
        var c = node.get("children"),
235
            fc = c.item(0),
236
            mc = c.item(1),
237
            lc = c.item(2),
238
            size = node.getData("isHoriz") ? "offsetWidth" : "offsetHeight";
239
 
240
        node.setStyle(TRANSITION_PROPERTY, TRANSFORM);
241
        mc.setStyle(TRANSITION_PROPERTY, TRANSFORM);
242
        lc.setStyle(TRANSITION_PROPERTY, TRANSFORM);
243
 
244
        node.setData(CHILD_CACHE, {
245
            fc : fc,
246
            lc : lc,
247
            mc : mc,
248
            fcSize : fc && fc.get(size),
249
            lcSize : lc && lc.get(size)
250
        });
251
    },
252
 
253
    /**
254
     * Clears child cache
255
     *
256
     * @method _clearChildCache
257
     * @private
258
     * @param {Node} node
259
     */
260
    _clearChildCache : function(node) {
261
        node.clearData(CHILD_CACHE);
262
    },
263
 
264
    /**
265
     * Utility method, to move/resize either vertical or horizontal scrollbars
266
     *
267
     * @method _updateBar
268
     * @private
269
     *
270
     * @param {Node} scrollbar The scrollbar node.
271
     * @param {Number} current The current scroll position.
272
     * @param {Number} duration The transition duration.
273
     * @param {boolean} horiz true if horizontal, false if vertical.
274
     */
275
    _updateBar : function(scrollbar, current, duration, horiz) {
276
 
277
        var host = this._host,
278
            basic = this._basic,
279
 
280
            scrollbarSize = 0,
281
            scrollbarPos = 1,
282
 
283
            childCache = scrollbar.getData(CHILD_CACHE),
284
            lastChild = childCache.lc,
285
            middleChild = childCache.mc,
286
            firstChildSize = childCache.fcSize,
287
            lastChildSize = childCache.lcSize,
288
            middleChildSize,
289
            lastChildPosition,
290
 
291
            transition,
292
            translate,
293
            scale,
294
 
295
            dim,
296
            dimOffset,
297
            dimCache,
298
            widgetSize,
299
            contentSize;
300
 
301
        if (horiz) {
302
            dim = WIDTH;
303
            dimOffset = LEFT;
304
            dimCache = HORIZ_CACHE;
305
            widgetSize = this._dims.offsetWidth;
306
            contentSize = this._dims.scrollWidth;
307
            translate = TRANSLATE_X;
308
            scale = SCALE_X;
309
            current = (current !== undefined) ? current : host.get(SCROLL_X);
310
        } else {
311
            dim = HEIGHT;
312
            dimOffset = TOP;
313
            dimCache = VERT_CACHE;
314
            widgetSize = this._dims.offsetHeight;
315
            contentSize = this._dims.scrollHeight;
316
            translate = TRANSLATE_Y;
317
            scale = SCALE_Y;
318
            current = (current !== undefined) ? current : host.get(SCROLL_Y);
319
        }
320
 
321
        scrollbarSize = Math.floor(widgetSize * (widgetSize/contentSize));
322
        scrollbarPos = Math.floor((current/(contentSize - widgetSize)) * (widgetSize - scrollbarSize));
323
        if (scrollbarSize > widgetSize) {
324
            scrollbarSize = 1;
325
        }
326
 
327
        if (scrollbarPos > (widgetSize - scrollbarSize)) {
328
            scrollbarSize = scrollbarSize - (scrollbarPos - (widgetSize - scrollbarSize));
329
        } else if (scrollbarPos < 0) {
330
            scrollbarSize = scrollbarPos + scrollbarSize;
331
            scrollbarPos = 0;
332
        } else if (isNaN(scrollbarPos)) {
333
            scrollbarPos = 0;
334
        }
335
 
336
        middleChildSize = (scrollbarSize - (firstChildSize + lastChildSize));
337
 
338
        if (middleChildSize < 0) {
339
            middleChildSize = 0;
340
        }
341
 
342
        if (middleChildSize === 0 && scrollbarPos !== 0) {
343
            scrollbarPos = widgetSize - (firstChildSize + lastChildSize) - 1;
344
        }
345
 
346
        if (duration !== 0) {
347
            // Position Scrollbar
348
            transition = {
349
                duration : duration
350
            };
351
 
352
            if (NATIVE_TRANSITIONS) {
353
                transition.transform = translate + scrollbarPos + PX_CLOSE;
354
            } else {
355
                transition[dimOffset] = scrollbarPos + PX;
356
            }
357
 
358
            scrollbar.transition(transition);
359
 
360
        } else {
361
            if (NATIVE_TRANSITIONS) {
362
                scrollbar.setStyle(TRANSFORM, translate + scrollbarPos + PX_CLOSE);
363
            } else {
364
                scrollbar.setStyle(dimOffset, scrollbarPos + PX);
365
            }
366
        }
367
 
368
        // Resize Scrollbar Middle Child
369
        if (this[dimCache] !== middleChildSize) {
370
            this[dimCache] = middleChildSize;
371
 
372
            if (middleChildSize > 0) {
373
 
374
                if (duration !== 0) {
375
                    transition = {
376
                        duration : duration
377
                    };
378
 
379
                    if(NATIVE_TRANSITIONS) {
380
                        transition.transform = scale + middleChildSize + CLOSE;
381
                    } else {
382
                        transition[dim] = middleChildSize + PX;
383
                    }
384
 
385
                    middleChild.transition(transition);
386
                } else {
387
                    if (NATIVE_TRANSITIONS) {
388
                        middleChild.setStyle(TRANSFORM, scale + middleChildSize + CLOSE);
389
                    } else {
390
                        middleChild.setStyle(dim, middleChildSize + PX);
391
                    }
392
                }
393
 
394
                // Position Last Child
395
                if (!horiz || !basic) {
396
 
397
                    lastChildPosition = scrollbarSize - lastChildSize;
398
 
399
                    if(duration !== 0) {
400
                        transition = {
401
                            duration : duration
402
                        };
403
 
404
                        if (NATIVE_TRANSITIONS) {
405
                            transition.transform = translate + lastChildPosition + PX_CLOSE;
406
                        } else {
407
                            transition[dimOffset] = lastChildPosition;
408
                        }
409
 
410
                        lastChild.transition(transition);
411
                    } else {
412
                        if (NATIVE_TRANSITIONS) {
413
                            lastChild.setStyle(TRANSFORM, translate + lastChildPosition + PX_CLOSE);
414
                        } else {
415
                            lastChild.setStyle(dimOffset, lastChildPosition + PX);
416
                        }
417
                    }
418
                }
419
            }
420
        }
421
    },
422
 
423
    /**
424
     * AOP method, invoked after the host's _uiScrollTo method,
425
     *  to position and resize the scroll bars
426
     *
427
     * @method _update
428
     * @param x {Number} The current scrollX value
429
     * @param y {Number} The current scrollY value
430
     * @param duration {Number} Number of ms of animation (optional) - used when snapping to bounds
431
     * @param easing {String} Optional easing equation to use during the animation, if duration is set
432
     * @protected
433
     */
434
    _update: function(x, y, duration) {
435
        var vNode = this.get(VERTICAL_NODE),
436
            hNode = this.get(HORIZONTAL_NODE),
437
            host = this._host,
438
            axis = host._cAxis;
439
 
440
        duration = (duration || 0)/1000;
441
 
442
        if (!this._showing) {
443
            this.show();
444
        }
445
 
446
        if (axis && axis.y && vNode && y !== null) {
447
            this._updateBar(vNode, y, duration, false);
448
        }
449
 
450
        if (axis && axis.x && hNode && x !== null) {
451
            this._updateBar(hNode, x, duration, true);
452
        }
453
    },
454
 
455
    /**
456
     * Show the scroll bar indicators
457
     *
458
     * @method show
459
     * @param animated {Boolean} Whether or not to animate the showing
460
     */
461
    show: function(animated) {
462
        this._show(true, animated);
463
    },
464
 
465
    /**
466
     * Hide the scroll bar indicators
467
     *
468
     * @method hide
469
     * @param animated {Boolean} Whether or not to animate the hiding
470
     */
471
    hide: function(animated) {
472
        this._show(false, animated);
473
    },
474
 
475
    /**
476
     * Internal hide/show implementation utility method
477
     *
478
     * @method _show
479
     * @param {boolean} show Whether to show or hide the scrollbar
480
     * @param {bolean} animated Whether or not to animate while showing/hide
481
     * @protected
482
     */
483
    _show : function(show, animated) {
484
 
485
        var verticalNode = this.get(VERTICAL_NODE),
486
            horizontalNode = this.get(HORIZONTAL_NODE),
487
 
488
            duration = (animated) ? 0.6 : 0,
489
            opacity = (show) ? 1 : 0,
490
 
491
            transition;
492
 
493
        this._showing = show;
494
 
495
        if (this._flashTimer) {
496
            this._flashTimer.cancel();
497
        }
498
 
499
        transition = {
500
            duration : duration,
501
            opacity : opacity
502
        };
503
 
504
        if (verticalNode && verticalNode._node) {
505
            verticalNode.transition(transition);
506
        }
507
 
508
        if (horizontalNode && horizontalNode._node) {
509
            horizontalNode.transition(transition);
510
        }
511
    },
512
 
513
    /**
514
     * Momentarily flash the scroll bars to indicate current scroll position
515
     *
516
     * @method flash
517
     */
518
    flash: function() {
519
        this.show(true);
520
        this._flashTimer = Y.later(800, this, 'hide', true);
521
    },
522
 
523
    /**
524
     * Setter for the verticalNode and horizontalNode attributes
525
     *
526
     * @method _setNode
527
     * @param node {Node} The Y.Node instance for the scrollbar
528
     * @param name {String} The attribute name
529
     * @return {Node} The Y.Node instance for the scrollbar
530
     *
531
     * @protected
532
     */
533
    _setNode: function(node, name) {
534
        var horiz = (name === HORIZONTAL_NODE);
535
            node = Y.one(node);
536
 
537
        if (node) {
538
            node.addClass(_classNames.scrollbar);
539
            node.addClass( (horiz) ? _classNames.scrollbarH : _classNames.scrollbarV );
540
            node.setData("isHoriz", horiz);
541
        }
542
 
543
        return node;
544
    },
545
 
546
    /**
547
     * Creates default node instances for scrollbars
548
     *
549
     * @method _defaultNode
550
     * @return {Node} The Y.Node instance for the scrollbar
551
     *
552
     * @protected
553
     */
554
    _defaultNode: function() {
555
        return Y.Node.create(ScrollbarsPlugin.SCROLLBAR_TEMPLATE);
556
    },
557
 
558
    _basic: Y.UA.ie && Y.UA.ie <= 8
559
 
560
});
561
 
562
 
563
}, '3.18.1', {"requires": ["classnamemanager", "transition", "plugin"], "skinnable": true});