| OLD | NEW | 
 | (Empty) | 
|    1 // Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file |  | 
|    2 // for details. All rights reserved. Use of this source code is governed by a |  | 
|    3 // BSD-style license that can be found in the LICENSE file. |  | 
|    4  |  | 
|    5 /** |  | 
|    6  * Adds a listener to the scroller with triggers events |  | 
|    7  * when a trigger point at the top, or bottom, of the screen is reached. |  | 
|    8  * |  | 
|    9  * To use this you will need to have an element with a scroller attached |  | 
|   10  * to it. You need to have defined (in pixels) how far from the top or |  | 
|   11  * bottom the scroll position must be in order to trigger (the "trigger |  | 
|   12  * point") The element using this must have functions for hitting the top |  | 
|   13  * trigger, and the bottom trigger. In general, these methods will |  | 
|   14  * ascertain whether we have more data to scroll to (i.e. when we hit |  | 
|   15  * the bottom trigger point but have reached the end of the data |  | 
|   16  * displayed in the element we should ignore it), make the call for |  | 
|   17  * more data and reposition the scroller - repositioning is key to |  | 
|   18  * good user experience. |  | 
|   19  * |  | 
|   20  * Triggers are generated by listening for the SCROLL_END event from the |  | 
|   21  * scroller, so data calls are not initiated whilst scrolling is happening, |  | 
|   22  * but after. |  | 
|   23  * |  | 
|   24  * Controls changing divs between the usual (non-loading) div and the |  | 
|   25  * loading div. To take advantage of this, callback function should return |  | 
|   26  * a boolean indicating whether the usual div should be replaced by the |  | 
|   27  * loading div. |  | 
|   28  */ |  | 
|   29 class InfiniteScroller { |  | 
|   30   Scroller _scroller; |  | 
|   31  |  | 
|   32   /** |  | 
|   33    * Function to invoke when trigger point is reached at the top of the view. |  | 
|   34    */ |  | 
|   35   Function _onTopScroll; |  | 
|   36  |  | 
|   37   /** |  | 
|   38    * Function to invoke when trigger point is reached at the bottom of the view. |  | 
|   39    */ |  | 
|   40   Function _onBottomScroll; |  | 
|   41  |  | 
|   42   /** Offset for trigger point at the top of the view. */ |  | 
|   43   double _offsetTop; |  | 
|   44  |  | 
|   45   /** Offset for trigger point at the bottom of the view. */ |  | 
|   46   double _offsetBottom; |  | 
|   47  |  | 
|   48   /** Saves the last Y position. */ |  | 
|   49   double _lastScrollY; |  | 
|   50   Element _topDiv; |  | 
|   51   Element _topLoadingDiv; |  | 
|   52   Element _bottomDiv; |  | 
|   53   Element _bottomLoadingDiv; |  | 
|   54  |  | 
|   55   InfiniteScroller(Scroller scroller, |  | 
|   56                    Function onTopScroll, Function onBottomScroll, |  | 
|   57                    double offsetTop, [double offsetBottom = null]) |  | 
|   58       : _scroller = scroller, |  | 
|   59         _onTopScroll = onTopScroll, |  | 
|   60         _onBottomScroll = onBottomScroll, |  | 
|   61         _offsetTop = offsetTop, |  | 
|   62         _offsetBottom = offsetBottom == null ? offsetTop : offsetBottom, |  | 
|   63         _lastScrollY = 0.0 { |  | 
|   64   } |  | 
|   65  |  | 
|   66   /** |  | 
|   67    * Adds the loading divs. |  | 
|   68    * [topDiv] The div usually shown at the top. |  | 
|   69    * [topLoadingDiv] is the div to show at the top when waiting for more |  | 
|   70    * content to load at the top of the page. |  | 
|   71    * [bottomDiv] is the div usually shown at the bottom. |  | 
|   72    * [bottomLoadingDiv] is the div to show at the bottom when waiting for more |  | 
|   73    * content to load at the end of the page. |  | 
|   74    */ |  | 
|   75   void addLoadingDivs([Element topDiv = null, |  | 
|   76                        Element topLoadingDiv = null, |  | 
|   77                        Element bottomDiv = null, |  | 
|   78                        Element bottomLoadingDiv = null]) { |  | 
|   79     _topDiv = topDiv; |  | 
|   80     _topLoadingDiv = topLoadingDiv; |  | 
|   81     _bottomDiv = bottomDiv; |  | 
|   82     _bottomLoadingDiv = bottomLoadingDiv; |  | 
|   83     _updateVisibility(false, _topDiv, _topLoadingDiv); |  | 
|   84     _updateVisibility(false, _bottomDiv, _bottomLoadingDiv); |  | 
|   85   } |  | 
|   86  |  | 
|   87   void initialize() { |  | 
|   88     _registerEventListeners(); |  | 
|   89   } |  | 
|   90  |  | 
|   91   /** |  | 
|   92    * Switch back the divs after loading complete. Delegate should call |  | 
|   93    * this function after loading is complete. |  | 
|   94    */ |  | 
|   95   void loadEnd() { |  | 
|   96     _updateVisibility(false, _topDiv, _topLoadingDiv); |  | 
|   97     _updateVisibility(false, _bottomDiv, _bottomLoadingDiv); |  | 
|   98   } |  | 
|   99  |  | 
|  100   /** |  | 
|  101    * Called at the end of a scroll event. |  | 
|  102    */ |  | 
|  103   void _onScrollEnd() { |  | 
|  104     double ypos = _scroller.getVerticalOffset(); |  | 
|  105  |  | 
|  106     // Scroll is below last point. |  | 
|  107     if (ypos < _lastScrollY) { |  | 
|  108       double bottomTrigger = _scroller.getMinPointY() + _offsetBottom; |  | 
|  109       // And below trigger point. |  | 
|  110       if (ypos <= bottomTrigger) { |  | 
|  111         _updateVisibility(_onBottomScroll(), _bottomDiv, _bottomLoadingDiv); |  | 
|  112       } |  | 
|  113     } else { |  | 
|  114       if (ypos > _lastScrollY) { |  | 
|  115         // Scroll is above last point. |  | 
|  116         double topTrigger = _scroller.getMaxPointY() - _offsetTop; |  | 
|  117         // And above trigger point. |  | 
|  118         if (ypos >= topTrigger) { |  | 
|  119           _updateVisibility(_onTopScroll(), _topDiv, _topLoadingDiv); |  | 
|  120         } |  | 
|  121       } |  | 
|  122     } |  | 
|  123     _lastScrollY = ypos; |  | 
|  124   } |  | 
|  125  |  | 
|  126   /** |  | 
|  127    * Register the event listeners. |  | 
|  128    */ |  | 
|  129   void _registerEventListeners() { |  | 
|  130     _scroller.onScrollerEnd.add((Event event) { _onScrollEnd(); }); |  | 
|  131   } |  | 
|  132  |  | 
|  133   /** |  | 
|  134    * Hides one div and shows another. |  | 
|  135    */ |  | 
|  136   void _updateVisibility(bool isLoading, Element element, |  | 
|  137                          Element loadingElement) { |  | 
|  138     if (element != null) { |  | 
|  139       element.style.display = isLoading ? "none" : ""; |  | 
|  140     } |  | 
|  141     if (loadingElement != null) { |  | 
|  142       loadingElement.style.display = isLoading ? "" : "none"; |  | 
|  143     } |  | 
|  144   } |  | 
|  145 } |  | 
| OLD | NEW |