Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / Scroller2.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5   <title>The source code</title>
6   <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
8   <style type="text/css">
9     .highlight { display: block; background-color: #ddd; }
10   </style>
11   <script type="text/javascript">
12     function highlight() {
13       document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
14     }
15   </script>
16 </head>
17 <body onload="prettyPrint(); highlight();">
18   <pre class="prettyprint lang-js"><span id='Ext-layout-container-boxOverflow-Scroller'>/**
19 </span> * @class Ext.layout.container.boxOverflow.Scroller
20  * @extends Ext.layout.container.boxOverflow.None
21  * @private
22  */
23 Ext.define('Ext.layout.container.boxOverflow.Scroller', {
24
25     /* Begin Definitions */
26
27     extend: 'Ext.layout.container.boxOverflow.None',
28     requires: ['Ext.util.ClickRepeater', 'Ext.Element'],
29     alternateClassName: 'Ext.layout.boxOverflow.Scroller',
30     mixins: {
31         observable: 'Ext.util.Observable'
32     },
33     
34     /* End Definitions */
35
36 <span id='Ext-layout-container-boxOverflow-Scroller-cfg-animateScroll'>    /**
37 </span>     * @cfg {Boolean} animateScroll
38      * True to animate the scrolling of items within the layout (ignored if enableScroll is false)
39      */
40     animateScroll: false,
41
42 <span id='Ext-layout-container-boxOverflow-Scroller-cfg-scrollIncrement'>    /**
43 </span>     * @cfg {Number} scrollIncrement
44      * The number of pixels to scroll by on scroller click
45      */
46     scrollIncrement: 20,
47
48 <span id='Ext-layout-container-boxOverflow-Scroller-cfg-wheelIncrement'>    /**
49 </span>     * @cfg {Number} wheelIncrement
50      * The number of pixels to increment on mouse wheel scrolling.
51      */
52     wheelIncrement: 10,
53
54 <span id='Ext-layout-container-boxOverflow-Scroller-cfg-scrollRepeatInterval'>    /**
55 </span>     * @cfg {Number} scrollRepeatInterval
56      * Number of milliseconds between each scroll while a scroller button is held down
57      */
58     scrollRepeatInterval: 60,
59
60 <span id='Ext-layout-container-boxOverflow-Scroller-cfg-scrollDuration'>    /**
61 </span>     * @cfg {Number} scrollDuration
62      * Number of milliseconds that each scroll animation lasts
63      */
64     scrollDuration: 400,
65
66 <span id='Ext-layout-container-boxOverflow-Scroller-cfg-beforeCtCls'>    /**
67 </span>     * @cfg {String} beforeCtCls
68      * CSS class added to the beforeCt element. This is the element that holds any special items such as scrollers,
69      * which must always be present at the leftmost edge of the Container
70      */
71
72 <span id='Ext-layout-container-boxOverflow-Scroller-cfg-afterCtCls'>    /**
73 </span>     * @cfg {String} afterCtCls
74      * CSS class added to the afterCt element. This is the element that holds any special items such as scrollers,
75      * which must always be present at the rightmost edge of the Container
76      */
77
78 <span id='Ext-layout-container-boxOverflow-Scroller-cfg-scrollerCls'>    /**
79 </span>     * @cfg {String} [scrollerCls='x-box-scroller']
80      * CSS class added to both scroller elements if enableScroll is used
81      */
82     scrollerCls: Ext.baseCSSPrefix + 'box-scroller',
83
84 <span id='Ext-layout-container-boxOverflow-Scroller-cfg-beforeScrollerCls'>    /**
85 </span>     * @cfg {String} beforeScrollerCls
86      * CSS class added to the left scroller element if enableScroll is used
87      */
88
89 <span id='Ext-layout-container-boxOverflow-Scroller-cfg-afterScrollerCls'>    /**
90 </span>     * @cfg {String} afterScrollerCls
91      * CSS class added to the right scroller element if enableScroll is used
92      */
93     
94     constructor: function(layout, config) {
95         this.layout = layout;
96         Ext.apply(this, config || {});
97         
98         this.addEvents(
99 <span id='Ext-layout-container-boxOverflow-Scroller-event-scroll'>            /**
100 </span>             * @event scroll
101              * @param {Ext.layout.container.boxOverflow.Scroller} scroller The layout scroller
102              * @param {Number} newPosition The new position of the scroller
103              * @param {Boolean/Object} animate If animating or not. If true, it will be a animation configuration, else it will be false
104              */
105             'scroll'
106         );
107     },
108     
109     initCSSClasses: function() {
110         var me = this,
111         layout = me.layout;
112
113         if (!me.CSSinitialized) {
114             me.beforeCtCls = me.beforeCtCls || Ext.baseCSSPrefix + 'box-scroller-' + layout.parallelBefore;
115             me.afterCtCls  = me.afterCtCls  || Ext.baseCSSPrefix + 'box-scroller-' + layout.parallelAfter;
116             me.beforeScrollerCls = me.beforeScrollerCls || Ext.baseCSSPrefix + layout.owner.getXType() + '-scroll-' + layout.parallelBefore;
117             me.afterScrollerCls  = me.afterScrollerCls  || Ext.baseCSSPrefix + layout.owner.getXType() + '-scroll-' + layout.parallelAfter;
118             me.CSSinitializes = true;
119         }
120     },
121
122     handleOverflow: function(calculations, targetSize) {
123         var me = this,
124             layout = me.layout,
125             methodName = 'get' + layout.parallelPrefixCap,
126             newSize = {};
127
128         me.initCSSClasses();
129         me.callParent(arguments);
130         this.createInnerElements();
131         this.showScrollers();
132         newSize[layout.perpendicularPrefix] = targetSize[layout.perpendicularPrefix];
133         newSize[layout.parallelPrefix] = targetSize[layout.parallelPrefix] - (me.beforeCt[methodName]() + me.afterCt[methodName]());
134         return { targetSize: newSize };
135     },
136
137 <span id='Ext-layout-container-boxOverflow-Scroller-method-createInnerElements'>    /**
138 </span>     * @private
139      * Creates the beforeCt and afterCt elements if they have not already been created
140      */
141     createInnerElements: function() {
142         var me = this,
143             target = me.layout.getRenderTarget();
144
145         //normal items will be rendered to the innerCt. beforeCt and afterCt allow for fixed positioning of
146         //special items such as scrollers or dropdown menu triggers
147         if (!me.beforeCt) {
148             target.addCls(Ext.baseCSSPrefix + me.layout.direction + '-box-overflow-body');
149             me.beforeCt = target.insertSibling({cls: Ext.layout.container.Box.prototype.innerCls + ' ' + me.beforeCtCls}, 'before');
150             me.afterCt  = target.insertSibling({cls: Ext.layout.container.Box.prototype.innerCls + ' ' + me.afterCtCls},  'after');
151             me.createWheelListener();
152         }
153     },
154
155 <span id='Ext-layout-container-boxOverflow-Scroller-method-createWheelListener'>    /**
156 </span>     * @private
157      * Sets up an listener to scroll on the layout's innerCt mousewheel event
158      */
159     createWheelListener: function() {
160         this.layout.innerCt.on({
161             scope     : this,
162             mousewheel: function(e) {
163                 e.stopEvent();
164
165                 this.scrollBy(e.getWheelDelta() * this.wheelIncrement * -1, false);
166             }
167         });
168     },
169
170 <span id='Ext-layout-container-boxOverflow-Scroller-method-clearOverflow'>    /**
171 </span>     * @private
172      */
173     clearOverflow: function() {
174         this.hideScrollers();
175     },
176
177 <span id='Ext-layout-container-boxOverflow-Scroller-method-showScrollers'>    /**
178 </span>     * @private
179      * Shows the scroller elements in the beforeCt and afterCt. Creates the scrollers first if they are not already
180      * present. 
181      */
182     showScrollers: function() {
183         this.createScrollers();
184         this.beforeScroller.show();
185         this.afterScroller.show();
186         this.updateScrollButtons();
187         
188         this.layout.owner.addClsWithUI('scroller');
189     },
190
191 <span id='Ext-layout-container-boxOverflow-Scroller-method-hideScrollers'>    /**
192 </span>     * @private
193      * Hides the scroller elements in the beforeCt and afterCt
194      */
195     hideScrollers: function() {
196         if (this.beforeScroller != undefined) {
197             this.beforeScroller.hide();
198             this.afterScroller.hide();
199             
200             this.layout.owner.removeClsWithUI('scroller');
201         }
202     },
203
204 <span id='Ext-layout-container-boxOverflow-Scroller-method-createScrollers'>    /**
205 </span>     * @private
206      * Creates the clickable scroller elements and places them into the beforeCt and afterCt
207      */
208     createScrollers: function() {
209         if (!this.beforeScroller &amp;&amp; !this.afterScroller) {
210             var before = this.beforeCt.createChild({
211                 cls: Ext.String.format(&quot;{0} {1} &quot;, this.scrollerCls, this.beforeScrollerCls)
212             });
213
214             var after = this.afterCt.createChild({
215                 cls: Ext.String.format(&quot;{0} {1}&quot;, this.scrollerCls, this.afterScrollerCls)
216             });
217
218             before.addClsOnOver(this.beforeScrollerCls + '-hover');
219             after.addClsOnOver(this.afterScrollerCls + '-hover');
220
221             before.setVisibilityMode(Ext.Element.DISPLAY);
222             after.setVisibilityMode(Ext.Element.DISPLAY);
223
224             this.beforeRepeater = Ext.create('Ext.util.ClickRepeater', before, {
225                 interval: this.scrollRepeatInterval,
226                 handler : this.scrollLeft,
227                 scope   : this
228             });
229
230             this.afterRepeater = Ext.create('Ext.util.ClickRepeater', after, {
231                 interval: this.scrollRepeatInterval,
232                 handler : this.scrollRight,
233                 scope   : this
234             });
235
236 <span id='Ext-layout-container-boxOverflow-Scroller-property-beforeScroller'>            /**
237 </span>             * @property beforeScroller
238              * @type Ext.Element
239              * The left scroller element. Only created when needed.
240              */
241             this.beforeScroller = before;
242
243 <span id='Ext-layout-container-boxOverflow-Scroller-property-afterScroller'>            /**
244 </span>             * @property afterScroller
245              * @type Ext.Element
246              * The left scroller element. Only created when needed.
247              */
248             this.afterScroller = after;
249         }
250     },
251
252 <span id='Ext-layout-container-boxOverflow-Scroller-method-destroy'>    /**
253 </span>     * @private
254      */
255     destroy: function() {
256         Ext.destroy(this.beforeRepeater, this.afterRepeater, this.beforeScroller, this.afterScroller, this.beforeCt, this.afterCt);
257     },
258
259 <span id='Ext-layout-container-boxOverflow-Scroller-method-scrollBy'>    /**
260 </span>     * @private
261      * Scrolls left or right by the number of pixels specified
262      * @param {Number} delta Number of pixels to scroll to the right by. Use a negative number to scroll left
263      */
264     scrollBy: function(delta, animate) {
265         this.scrollTo(this.getScrollPosition() + delta, animate);
266     },
267
268 <span id='Ext-layout-container-boxOverflow-Scroller-method-getScrollAnim'>    /**
269 </span>     * @private
270      * @return {Object} Object passed to scrollTo when scrolling
271      */
272     getScrollAnim: function() {
273         return {
274             duration: this.scrollDuration, 
275             callback: this.updateScrollButtons, 
276             scope   : this
277         };
278     },
279
280 <span id='Ext-layout-container-boxOverflow-Scroller-method-updateScrollButtons'>    /**
281 </span>     * @private
282      * Enables or disables each scroller button based on the current scroll position
283      */
284     updateScrollButtons: function() {
285         if (this.beforeScroller == undefined || this.afterScroller == undefined) {
286             return;
287         }
288
289         var beforeMeth = this.atExtremeBefore()  ? 'addCls' : 'removeCls',
290             afterMeth  = this.atExtremeAfter() ? 'addCls' : 'removeCls',
291             beforeCls  = this.beforeScrollerCls + '-disabled',
292             afterCls   = this.afterScrollerCls  + '-disabled';
293         
294         this.beforeScroller[beforeMeth](beforeCls);
295         this.afterScroller[afterMeth](afterCls);
296         this.scrolling = false;
297     },
298
299 <span id='Ext-layout-container-boxOverflow-Scroller-method-atExtremeBefore'>    /**
300 </span>     * @private
301      * Returns true if the innerCt scroll is already at its left-most point
302      * @return {Boolean} True if already at furthest left point
303      */
304     atExtremeBefore: function() {
305         return this.getScrollPosition() === 0;
306     },
307
308 <span id='Ext-layout-container-boxOverflow-Scroller-method-scrollLeft'>    /**
309 </span>     * @private
310      * Scrolls to the left by the configured amount
311      */
312     scrollLeft: function() {
313         this.scrollBy(-this.scrollIncrement, false);
314     },
315
316 <span id='Ext-layout-container-boxOverflow-Scroller-method-scrollRight'>    /**
317 </span>     * @private
318      * Scrolls to the right by the configured amount
319      */
320     scrollRight: function() {
321         this.scrollBy(this.scrollIncrement, false);
322     },
323
324 <span id='Ext-layout-container-boxOverflow-Scroller-method-getScrollPosition'>    /**
325 </span>     * Returns the current scroll position of the innerCt element
326      * @return {Number} The current scroll position
327      */
328     getScrollPosition: function(){
329         var layout = this.layout;
330         return parseInt(layout.innerCt.dom['scroll' + layout.parallelBeforeCap], 10) || 0;
331     },
332
333 <span id='Ext-layout-container-boxOverflow-Scroller-method-getMaxScrollPosition'>    /**
334 </span>     * @private
335      * Returns the maximum value we can scrollTo
336      * @return {Number} The max scroll value
337      */
338     getMaxScrollPosition: function() {
339         var layout = this.layout;
340         return layout.innerCt.dom['scroll' + layout.parallelPrefixCap] - this.layout.innerCt['get' + layout.parallelPrefixCap]();
341     },
342
343 <span id='Ext-layout-container-boxOverflow-Scroller-method-atExtremeAfter'>    /**
344 </span>     * @private
345      * Returns true if the innerCt scroll is already at its right-most point
346      * @return {Boolean} True if already at furthest right point
347      */
348     atExtremeAfter: function() {
349         return this.getScrollPosition() &gt;= this.getMaxScrollPosition();
350     },
351
352 <span id='Ext-layout-container-boxOverflow-Scroller-method-scrollTo'>    /**
353 </span>     * @private
354      * Scrolls to the given position. Performs bounds checking.
355      * @param {Number} position The position to scroll to. This is constrained.
356      * @param {Boolean} animate True to animate. If undefined, falls back to value of this.animateScroll
357      */
358     scrollTo: function(position, animate) {
359         var me = this,
360             layout = me.layout,
361             oldPosition = me.getScrollPosition(),
362             newPosition = Ext.Number.constrain(position, 0, me.getMaxScrollPosition());
363
364         if (newPosition != oldPosition &amp;&amp; !me.scrolling) {
365             if (animate == undefined) {
366                 animate = me.animateScroll;
367             }
368
369             layout.innerCt.scrollTo(layout.parallelBefore, newPosition, animate ? me.getScrollAnim() : false);
370             if (animate) {
371                 me.scrolling = true;
372             } else {
373                 me.scrolling = false;
374                 me.updateScrollButtons();
375             }
376             
377             me.fireEvent('scroll', me, newPosition, animate ? me.getScrollAnim() : false);
378         }
379     },
380
381 <span id='Ext-layout-container-boxOverflow-Scroller-method-scrollToItem'>    /**
382 </span>     * Scrolls to the given component.
383      * @param {String/Number/Ext.Component} item The item to scroll to. Can be a numerical index, component id 
384      * or a reference to the component itself.
385      * @param {Boolean} animate True to animate the scrolling
386      */
387     scrollToItem: function(item, animate) {
388         var me = this,
389             layout = me.layout,
390             visibility,
391             box,
392             newPos;
393
394         item = me.getItem(item);
395         if (item != undefined) {
396             visibility = this.getItemVisibility(item);
397             if (!visibility.fullyVisible) {
398                 box  = item.getBox(true, true);
399                 newPos = box[layout.parallelPosition];
400                 if (visibility.hiddenEnd) {
401                     newPos -= (this.layout.innerCt['get' + layout.parallelPrefixCap]() - box[layout.parallelPrefix]);
402                 }
403                 this.scrollTo(newPos, animate);
404             }
405         }
406     },
407
408 <span id='Ext-layout-container-boxOverflow-Scroller-method-getItemVisibility'>    /**
409 </span>     * @private
410      * For a given item in the container, return an object with information on whether the item is visible
411      * with the current innerCt scroll value.
412      * @param {Ext.Component} item The item
413      * @return {Object} Values for fullyVisible, hiddenStart and hiddenEnd
414      */
415     getItemVisibility: function(item) {
416         var me          = this,
417             box         = me.getItem(item).getBox(true, true),
418             layout      = me.layout,
419             itemStart   = box[layout.parallelPosition],
420             itemEnd     = itemStart + box[layout.parallelPrefix],
421             scrollStart = me.getScrollPosition(),
422             scrollEnd   = scrollStart + layout.innerCt['get' + layout.parallelPrefixCap]();
423
424         return {
425             hiddenStart : itemStart &lt; scrollStart,
426             hiddenEnd   : itemEnd &gt; scrollEnd,
427             fullyVisible: itemStart &gt; scrollStart &amp;&amp; itemEnd &lt; scrollEnd
428         };
429     }
430 });</pre>
431 </body>
432 </html>