Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / Scroller.html
index 4d6da8c..126cc1b 100644 (file)
@@ -3,8 +3,8 @@
 <head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   <title>The source code</title>
-  <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
-  <script type="text/javascript" src="../prettify/prettify.js"></script>
+  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
+  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
   <style type="text/css">
     .highlight { display: block; background-color: #ddd; }
   </style>
   </script>
 </head>
 <body onload="prettyPrint(); highlight();">
-  <pre class="prettyprint lang-js"><span id='Ext-layout-container-boxOverflow-Scroller'>/**
-</span> * @class Ext.layout.container.boxOverflow.Scroller
- * @extends Ext.layout.container.boxOverflow.None
- * @private
+  <pre class="prettyprint lang-js"><span id='Ext-grid-Scroller'>/**
+</span> * Docked in an Ext.grid.Panel, controls virtualized scrolling and synchronization
+ * across different sections.
  */
-Ext.define('Ext.layout.container.boxOverflow.Scroller', {
+Ext.define('Ext.grid.Scroller', {
+    extend: 'Ext.Component',
+    alias: 'widget.gridscroller',
+    weight: 110,
+    baseCls: Ext.baseCSSPrefix + 'scroller',
+    focusable: false,
+    reservedSpace: 0,
+
+    renderTpl: [
+        '&lt;div class=&quot;' + Ext.baseCSSPrefix + 'scroller-ct&quot; id=&quot;{baseId}_ct&quot;&gt;',
+            '&lt;div class=&quot;' + Ext.baseCSSPrefix + 'stretcher&quot; id=&quot;{baseId}_stretch&quot;&gt;&lt;/div&gt;',
+        '&lt;/div&gt;'
+    ],
+
+    initComponent: function() {
+        var me       = this,
+            dock     = me.dock,
+            cls      = Ext.baseCSSPrefix + 'scroller-vertical';
+
+        me.offsets = {bottom: 0};
+        me.scrollProp = 'scrollTop';
+        me.vertical = true;
+        me.sizeProp = 'width';
+
+        if (dock === 'top' || dock === 'bottom') {
+            cls = Ext.baseCSSPrefix + 'scroller-horizontal';
+            me.sizeProp = 'height';
+            me.scrollProp = 'scrollLeft';
+            me.vertical = false;
+            me.weight += 5;
+        }
 
-    /* Begin Definitions */
+        me.cls += (' ' + cls);
 
-    extend: 'Ext.layout.container.boxOverflow.None',
-    requires: ['Ext.util.ClickRepeater', 'Ext.core.Element'],
-    alternateClassName: 'Ext.layout.boxOverflow.Scroller',
-    mixins: {
-        observable: 'Ext.util.Observable'
+        Ext.applyIf(me.renderSelectors, {
+            stretchEl: '.' + Ext.baseCSSPrefix + 'stretcher',
+            scrollEl: '.' + Ext.baseCSSPrefix + 'scroller-ct'
+        });
+        me.callParent();
     },
     
-    /* End Definitions */
-
-<span id='Ext-layout-container-boxOverflow-Scroller-cfg-animateScroll'>    /**
-</span>     * @cfg {Boolean} animateScroll
-     * True to animate the scrolling of items within the layout (defaults to true, ignored if enableScroll is false)
-     */
-    animateScroll: false,
-
-<span id='Ext-layout-container-boxOverflow-Scroller-cfg-scrollIncrement'>    /**
-</span>     * @cfg {Number} scrollIncrement
-     * The number of pixels to scroll by on scroller click (defaults to 24)
-     */
-    scrollIncrement: 20,
+    ensureDimension: function(){
+        var me = this,
+            sizeProp = me.sizeProp;
+            
+        me[sizeProp] = me.scrollerSize = Ext.getScrollbarSize()[sizeProp];  
+    },
 
-<span id='Ext-layout-container-boxOverflow-Scroller-cfg-wheelIncrement'>    /**
-</span>     * @cfg {Number} wheelIncrement
-     * The number of pixels to increment on mouse wheel scrolling (defaults to &lt;tt&gt;3&lt;/tt&gt;).
-     */
-    wheelIncrement: 10,
+    initRenderData: function () {
+        var me = this,
+            ret = me.callParent(arguments) || {};
 
-<span id='Ext-layout-container-boxOverflow-Scroller-cfg-scrollRepeatInterval'>    /**
-</span>     * @cfg {Number} scrollRepeatInterval
-     * Number of milliseconds between each scroll while a scroller button is held down (defaults to 20)
-     */
-    scrollRepeatInterval: 60,
+        ret.baseId = me.id;
 
-<span id='Ext-layout-container-boxOverflow-Scroller-cfg-scrollDuration'>    /**
-</span>     * @cfg {Number} scrollDuration
-     * Number of milliseconds that each scroll animation lasts (defaults to 400)
-     */
-    scrollDuration: 400,
+        return ret;
+    },
 
-<span id='Ext-layout-container-boxOverflow-Scroller-cfg-beforeCtCls'>    /**
-</span>     * @cfg {String} beforeCtCls
-     * CSS class added to the beforeCt element. This is the element that holds any special items such as scrollers,
-     * which must always be present at the leftmost edge of the Container
-     */
+    afterRender: function() {
+        var me = this;
+        me.callParent();
+        
+        me.mon(me.scrollEl, 'scroll', me.onElScroll, me);
+        Ext.cache[me.el.id].skipGarbageCollection = true;
+    },
 
-<span id='Ext-layout-container-boxOverflow-Scroller-cfg-afterCtCls'>    /**
-</span>     * @cfg {String} afterCtCls
-     * CSS class added to the afterCt element. This is the element that holds any special items such as scrollers,
-     * which must always be present at the rightmost edge of the Container
-     */
+    onAdded: function(container) {
+        // Capture the controlling grid Panel so that we can use it even when we are undocked, and don't have an ownerCt
+        this.ownerGrid = container;
+        this.callParent(arguments);
+    },
 
-<span id='Ext-layout-container-boxOverflow-Scroller-cfg-scrollerCls'>    /**
-</span>     * @cfg {String} scrollerCls
-     * CSS class added to both scroller elements if enableScroll is used
-     */
-    scrollerCls: Ext.baseCSSPrefix + 'box-scroller',
+    getSizeCalculation: function() {
+        var me     = this,
+            owner  = me.getPanel(),
+            width  = 1,
+            height = 1,
+            view, tbl;
+
+        if (!me.vertical) {
+            // TODO: Must gravitate to a single region..
+            // Horizontal scrolling only scrolls virtualized region
+            var items  = owner.query('tableview'),
+                center = items[1] || items[0];
+
+            if (!center) {
+                return false;
+            }
+            // center is not guaranteed to have content, such as when there
+            // are zero rows in the grid/tree. We read the width from the
+            // headerCt instead.
+            width = center.headerCt.getFullWidth();
 
-<span id='Ext-layout-container-boxOverflow-Scroller-cfg-beforeScrollerCls'>    /**
-</span>     * @cfg {String} beforeScrollerCls
-     * CSS class added to the left scroller element if enableScroll is used
-     */
+            if (Ext.isIEQuirks) {
+                width--;
+            }
+        } else {
+            view = owner.down('tableview:not([lockableInjected])');
+            if (!view || !view.el) {
+                return false;
+            }
+            tbl = view.el.child('table', true);
+            if (!tbl) {
+                return false;
+            }
 
-<span id='Ext-layout-container-boxOverflow-Scroller-cfg-afterScrollerCls'>    /**
-</span>     * @cfg {String} afterScrollerCls
-     * CSS class added to the right scroller element if enableScroll is used
-     */
-    
-    constructor: function(layout, config) {
-        this.layout = layout;
-        Ext.apply(this, config || {});
-        
-        this.addEvents(
-<span id='Ext-layout-container-boxOverflow-Scroller-event-scroll'>            /**
-</span>             * @event scroll
-             * @param {Ext.layout.container.boxOverflow.Scroller} scroller The layout scroller
-             * @param {Number} newPosition The new position of the scroller
-             * @param {Boolean/Object} animate If animating or not. If true, it will be a animation configuration, else it will be false
-             */
-            'scroll'
-        );
-    },
-    
-    initCSSClasses: function() {
-        var me = this,
-        layout = me.layout;
-
-        if (!me.CSSinitialized) {
-            me.beforeCtCls = me.beforeCtCls || Ext.baseCSSPrefix + 'box-scroller-' + layout.parallelBefore;
-            me.afterCtCls  = me.afterCtCls  || Ext.baseCSSPrefix + 'box-scroller-' + layout.parallelAfter;
-            me.beforeScrollerCls = me.beforeScrollerCls || Ext.baseCSSPrefix + layout.owner.getXType() + '-scroll-' + layout.parallelBefore;
-            me.afterScrollerCls  = me.afterScrollerCls  || Ext.baseCSSPrefix + layout.owner.getXType() + '-scroll-' + layout.parallelAfter;
-            me.CSSinitializes = true;
+            // needs to also account for header and scroller (if still in picture)
+            // should calculate from headerCt.
+            height = tbl.offsetHeight;
+        }
+        if (isNaN(width)) {
+            width = 1;
+        }
+        if (isNaN(height)) {
+            height = 1;
         }
+        return {
+            width: width,
+            height: height
+        };
     },
 
-    handleOverflow: function(calculations, targetSize) {
+    invalidate: function(firstPass) {
         var me = this,
-            layout = me.layout,
-            methodName = 'get' + layout.parallelPrefixCap,
-            newSize = {};
-
-        me.initCSSClasses();
-        me.callParent(arguments);
-        this.createInnerElements();
-        this.showScrollers();
-        newSize[layout.perpendicularPrefix] = targetSize[layout.perpendicularPrefix];
-        newSize[layout.parallelPrefix] = targetSize[layout.parallelPrefix] - (me.beforeCt[methodName]() + me.afterCt[methodName]());
-        return { targetSize: newSize };
-    },
+            stretchEl = me.stretchEl;
 
-<span id='Ext-layout-container-boxOverflow-Scroller-method-createInnerElements'>    /**
-</span>     * @private
-     * Creates the beforeCt and afterCt elements if they have not already been created
-     */
-    createInnerElements: function() {
-        var me = this,
-            target = me.layout.getRenderTarget();
-
-        //normal items will be rendered to the innerCt. beforeCt and afterCt allow for fixed positioning of
-        //special items such as scrollers or dropdown menu triggers
-        if (!me.beforeCt) {
-            target.addCls(Ext.baseCSSPrefix + me.layout.direction + '-box-overflow-body');
-            me.beforeCt = target.insertSibling({cls: Ext.layout.container.Box.prototype.innerCls + ' ' + me.beforeCtCls}, 'before');
-            me.afterCt  = target.insertSibling({cls: Ext.layout.container.Box.prototype.innerCls + ' ' + me.afterCtCls},  'after');
-            me.createWheelListener();
+        if (!stretchEl || !me.ownerCt) {
+            return;
         }
-    },
 
-<span id='Ext-layout-container-boxOverflow-Scroller-method-createWheelListener'>    /**
-</span>     * @private
-     * Sets up an listener to scroll on the layout's innerCt mousewheel event
-     */
-    createWheelListener: function() {
-        this.layout.innerCt.on({
-            scope     : this,
-            mousewheel: function(e) {
-                e.stopEvent();
+        var size  = me.getSizeCalculation(),
+            scrollEl = me.scrollEl,
+            elDom = scrollEl.dom,
+            reservedSpace = me.reservedSpace,
+            pos,
+            extra = 5;
 
-                this.scrollBy(e.getWheelDelta() * this.wheelIncrement * -1, false);
-            }
-        });
-    },
+        if (size) {
+            stretchEl.setSize(size);
 
-<span id='Ext-layout-container-boxOverflow-Scroller-method-clearOverflow'>    /**
-</span>     * @private
-     */
-    clearOverflow: function() {
-        this.hideScrollers();
-    },
+            size = me.el.getSize(true);
 
-<span id='Ext-layout-container-boxOverflow-Scroller-method-showScrollers'>    /**
-</span>     * @private
-     * Shows the scroller elements in the beforeCt and afterCt. Creates the scrollers first if they are not already
-     * present. 
-     */
-    showScrollers: function() {
-        this.createScrollers();
-        this.beforeScroller.show();
-        this.afterScroller.show();
-        this.updateScrollButtons();
-        
-        this.layout.owner.addClsWithUI('scroller');
-    },
+            if (me.vertical) {
+                size.width += extra;
+                size.height -= reservedSpace;
+                pos = 'left';
+            } else {
+                size.width -= reservedSpace;
+                size.height += extra;
+                pos = 'top';
+            }
 
-<span id='Ext-layout-container-boxOverflow-Scroller-method-hideScrollers'>    /**
-</span>     * @private
-     * Hides the scroller elements in the beforeCt and afterCt
-     */
-    hideScrollers: function() {
-        if (this.beforeScroller != undefined) {
-            this.beforeScroller.hide();
-            this.afterScroller.hide();
-            
-            this.layout.owner.removeClsWithUI('scroller');
-        }
-    },
+            scrollEl.setSize(size);
+            elDom.style[pos] = (-extra) + 'px';
 
-<span id='Ext-layout-container-boxOverflow-Scroller-method-createScrollers'>    /**
-</span>     * @private
-     * Creates the clickable scroller elements and places them into the beforeCt and afterCt
-     */
-    createScrollers: function() {
-        if (!this.beforeScroller &amp;&amp; !this.afterScroller) {
-            var before = this.beforeCt.createChild({
-                cls: Ext.String.format(&quot;{0} {1} &quot;, this.scrollerCls, this.beforeScrollerCls)
-            });
-
-            var after = this.afterCt.createChild({
-                cls: Ext.String.format(&quot;{0} {1}&quot;, this.scrollerCls, this.afterScrollerCls)
-            });
-
-            before.addClsOnOver(this.beforeScrollerCls + '-hover');
-            after.addClsOnOver(this.afterScrollerCls + '-hover');
-
-            before.setVisibilityMode(Ext.core.Element.DISPLAY);
-            after.setVisibilityMode(Ext.core.Element.DISPLAY);
-
-            this.beforeRepeater = Ext.create('Ext.util.ClickRepeater', before, {
-                interval: this.scrollRepeatInterval,
-                handler : this.scrollLeft,
-                scope   : this
-            });
-
-            this.afterRepeater = Ext.create('Ext.util.ClickRepeater', after, {
-                interval: this.scrollRepeatInterval,
-                handler : this.scrollRight,
-                scope   : this
-            });
-
-<span id='Ext-layout-container-boxOverflow-Scroller-property-beforeScroller'>            /**
-</span>             * @property beforeScroller
-             * @type Ext.core.Element
-             * The left scroller element. Only created when needed.
-             */
-            this.beforeScroller = before;
-
-<span id='Ext-layout-container-boxOverflow-Scroller-property-afterScroller'>            /**
-</span>             * @property afterScroller
-             * @type Ext.core.Element
-             * The left scroller element. Only created when needed.
-             */
-            this.afterScroller = after;
+            // BrowserBug: IE7
+            // This makes the scroller enabled, when initially rendering.
+            elDom.scrollTop = elDom.scrollTop;
         }
     },
 
-<span id='Ext-layout-container-boxOverflow-Scroller-method-destroy'>    /**
-</span>     * @private
-     */
-    destroy: function() {
-        Ext.destroy(this.beforeRepeater, this.afterRepeater, this.beforeScroller, this.afterScroller, this.beforeCt, this.afterCt);
+    afterComponentLayout: function() {
+        this.callParent(arguments);
+        this.invalidate();
     },
 
-<span id='Ext-layout-container-boxOverflow-Scroller-method-scrollBy'>    /**
-</span>     * @private
-     * Scrolls left or right by the number of pixels specified
-     * @param {Number} delta Number of pixels to scroll to the right by. Use a negative number to scroll left
-     */
-    scrollBy: function(delta, animate) {
-        this.scrollTo(this.getScrollPosition() + delta, animate);
-    },
+    restoreScrollPos: function () {
+        var me = this,
+            el = this.scrollEl,
+            elDom = el &amp;&amp; el.dom;
 
-<span id='Ext-layout-container-boxOverflow-Scroller-method-getScrollAnim'>    /**
-</span>     * @private
-     * @return {Object} Object passed to scrollTo when scrolling
-     */
-    getScrollAnim: function() {
-        return {
-            duration: this.scrollDuration, 
-            callback: this.updateScrollButtons, 
-            scope   : this
-        };
+        if (me._scrollPos !== null &amp;&amp; elDom) {
+            elDom[me.scrollProp] = me._scrollPos;
+            me._scrollPos = null;
+        }
     },
 
-<span id='Ext-layout-container-boxOverflow-Scroller-method-updateScrollButtons'>    /**
-</span>     * @private
-     * Enables or disables each scroller button based on the current scroll position
-     */
-    updateScrollButtons: function() {
-        if (this.beforeScroller == undefined || this.afterScroller == undefined) {
-            return;
+    setReservedSpace: function (reservedSpace) {
+        var me = this;
+        if (me.reservedSpace !== reservedSpace) {
+            me.reservedSpace = reservedSpace;
+            me.invalidate();
         }
-
-        var beforeMeth = this.atExtremeBefore()  ? 'addCls' : 'removeCls',
-            afterMeth  = this.atExtremeAfter() ? 'addCls' : 'removeCls',
-            beforeCls  = this.beforeScrollerCls + '-disabled',
-            afterCls   = this.afterScrollerCls  + '-disabled';
-        
-        this.beforeScroller[beforeMeth](beforeCls);
-        this.afterScroller[afterMeth](afterCls);
-        this.scrolling = false;
     },
 
-<span id='Ext-layout-container-boxOverflow-Scroller-method-atExtremeBefore'>    /**
-</span>     * @private
-     * Returns true if the innerCt scroll is already at its left-most point
-     * @return {Boolean} True if already at furthest left point
-     */
-    atExtremeBefore: function() {
-        return this.getScrollPosition() === 0;
-    },
+    saveScrollPos: function () {
+        var me = this,
+            el = this.scrollEl,
+            elDom = el &amp;&amp; el.dom;
 
-<span id='Ext-layout-container-boxOverflow-Scroller-method-scrollLeft'>    /**
-</span>     * @private
-     * Scrolls to the left by the configured amount
-     */
-    scrollLeft: function() {
-        this.scrollBy(-this.scrollIncrement, false);
+        me._scrollPos = elDom ? elDom[me.scrollProp] : null;
     },
 
-<span id='Ext-layout-container-boxOverflow-Scroller-method-scrollRight'>    /**
-</span>     * @private
-     * Scrolls to the right by the configured amount
+<span id='Ext-grid-Scroller-method-setScrollTop'>    /**
+</span>     * Sets the scrollTop and constrains the value between 0 and max.
+     * @param {Number} scrollTop
+     * @return {Number} The resulting scrollTop value after being constrained
      */
-    scrollRight: function() {
-        this.scrollBy(this.scrollIncrement, false);
-    },
+    setScrollTop: function(scrollTop) {
+        var el = this.scrollEl,
+            elDom = el &amp;&amp; el.dom;
 
-<span id='Ext-layout-container-boxOverflow-Scroller-method-getScrollPosition'>    /**
-</span>     * Returns the current scroll position of the innerCt element
-     * @return {Number} The current scroll position
-     */
-    getScrollPosition: function(){
-        var layout = this.layout;
-        return parseInt(layout.innerCt.dom['scroll' + layout.parallelBeforeCap], 10) || 0;
+        if (elDom) {
+            return elDom.scrollTop = Ext.Number.constrain(scrollTop, 0, elDom.scrollHeight - elDom.clientHeight);
+        }
     },
 
-<span id='Ext-layout-container-boxOverflow-Scroller-method-getMaxScrollPosition'>    /**
-</span>     * @private
-     * Returns the maximum value we can scrollTo
-     * @return {Number} The max scroll value
+<span id='Ext-grid-Scroller-method-setScrollLeft'>    /**
+</span>     * Sets the scrollLeft and constrains the value between 0 and max.
+     * @param {Number} scrollLeft
+     * @return {Number} The resulting scrollLeft value after being constrained
      */
-    getMaxScrollPosition: function() {
-        var layout = this.layout;
-        return layout.innerCt.dom['scroll' + layout.parallelPrefixCap] - this.layout.innerCt['get' + layout.parallelPrefixCap]();
-    },
+    setScrollLeft: function(scrollLeft) {
+        var el = this.scrollEl,
+            elDom = el &amp;&amp; el.dom;
 
-<span id='Ext-layout-container-boxOverflow-Scroller-method-atExtremeAfter'>    /**
-</span>     * @private
-     * Returns true if the innerCt scroll is already at its right-most point
-     * @return {Boolean} True if already at furthest right point
-     */
-    atExtremeAfter: function() {
-        return this.getScrollPosition() &gt;= this.getMaxScrollPosition();
+        if (elDom) {
+            return elDom.scrollLeft = Ext.Number.constrain(scrollLeft, 0, elDom.scrollWidth - elDom.clientWidth);
+        }
     },
 
-<span id='Ext-layout-container-boxOverflow-Scroller-method-scrollTo'>    /**
-</span>     * @private
-     * Scrolls to the given position. Performs bounds checking.
-     * @param {Number} position The position to scroll to. This is constrained.
-     * @param {Boolean} animate True to animate. If undefined, falls back to value of this.animateScroll
+<span id='Ext-grid-Scroller-method-scrollByDeltaY'>    /**
+</span>     * Scroll by deltaY
+     * @param {Number} delta
+     * @return {Number} The resulting scrollTop value
      */
-    scrollTo: function(position, animate) {
-        var me = this,
-            layout = me.layout,
-            oldPosition = me.getScrollPosition(),
-            newPosition = Ext.Number.constrain(position, 0, me.getMaxScrollPosition());
-
-        if (newPosition != oldPosition &amp;&amp; !me.scrolling) {
-            if (animate == undefined) {
-                animate = me.animateScroll;
-            }
+    scrollByDeltaY: function(delta) {
+        var el = this.scrollEl,
+            elDom = el &amp;&amp; el.dom;
 
-            layout.innerCt.scrollTo(layout.parallelBefore, newPosition, animate ? me.getScrollAnim() : false);
-            if (animate) {
-                me.scrolling = true;
-            } else {
-                me.scrolling = false;
-                me.updateScrollButtons();
-            }
-            
-            me.fireEvent('scroll', me, newPosition, animate ? me.getScrollAnim() : false);
+        if (elDom) {
+            return this.setScrollTop(elDom.scrollTop + delta);
         }
     },
 
-<span id='Ext-layout-container-boxOverflow-Scroller-method-scrollToItem'>    /**
-</span>     * Scrolls to the given component.
-     * @param {String|Number|Ext.Component} item The item to scroll to. Can be a numerical index, component id 
-     * or a reference to the component itself.
-     * @param {Boolean} animate True to animate the scrolling
+<span id='Ext-grid-Scroller-method-scrollByDeltaX'>    /**
+</span>     * Scroll by deltaX
+     * @param {Number} delta
+     * @return {Number} The resulting scrollLeft value
      */
-    scrollToItem: function(item, animate) {
-        var me = this,
-            layout = me.layout,
-            visibility,
-            box,
-            newPos;
-
-        item = me.getItem(item);
-        if (item != undefined) {
-            visibility = this.getItemVisibility(item);
-            if (!visibility.fullyVisible) {
-                box  = item.getBox(true, true);
-                newPos = box[layout.parallelPosition];
-                if (visibility.hiddenEnd) {
-                    newPos -= (this.layout.innerCt['get' + layout.parallelPrefixCap]() - box[layout.parallelPrefix]);
-                }
-                this.scrollTo(newPos, animate);
-            }
+    scrollByDeltaX: function(delta) {
+        var el = this.scrollEl,
+            elDom = el &amp;&amp; el.dom;
+
+        if (elDom) {
+            return this.setScrollLeft(elDom.scrollLeft + delta);
         }
     },
 
-<span id='Ext-layout-container-boxOverflow-Scroller-method-getItemVisibility'>    /**
-</span>     * @private
-     * For a given item in the container, return an object with information on whether the item is visible
-     * with the current innerCt scroll value.
-     * @param {Ext.Component} item The item
-     * @return {Object} Values for fullyVisible, hiddenStart and hiddenEnd
+
+<span id='Ext-grid-Scroller-method-scrollToTop'>    /**
+</span>     * Scroll to the top.
      */
-    getItemVisibility: function(item) {
-        var me          = this,
-            box         = me.getItem(item).getBox(true, true),
-            layout      = me.layout,
-            itemStart   = box[layout.parallelPosition],
-            itemEnd     = itemStart + box[layout.parallelPrefix],
-            scrollStart = me.getScrollPosition(),
-            scrollEnd   = scrollStart + layout.innerCt['get' + layout.parallelPrefixCap]();
+    scrollToTop : function(){
+        this.setScrollTop(0);
+    },
 
-        return {
-            hiddenStart : itemStart &lt; scrollStart,
-            hiddenEnd   : itemEnd &gt; scrollEnd,
-            fullyVisible: itemStart &gt; scrollStart &amp;&amp; itemEnd &lt; scrollEnd
-        };
+    // synchronize the scroller with the bound gridviews
+    onElScroll: function(event, target) {
+        this.fireEvent('bodyscroll', event, target);
+    },
+
+    getPanel: function() {
+        var me = this;
+        if (!me.panel) {
+            me.panel = this.up('[scrollerOwner]');
+        }
+        return me.panel;
     }
-});</pre>
+});
+
+</pre>
 </body>
 </html>