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