Export 0.1.61
[platform/framework/web/web-ui-fw.git] / src / widgets / common / js / jquery.mobile.tizen.scrollview.js
index 6bc7f04..cf7a4c4 100644 (file)
        };
 
        function getCurrentTime() {
-               return ( new Date() ).getTime();
+               return Date.now();
        }
 
        jQuery.widget( "tizen.scrollview", jQuery.mobile.widget, {
                options: {
-                       fps:               60,    // Frames per second in msecs.
                        direction:         null,  // "x", "y", or null for both.
 
-                       scrollDuration:    2000,  // Duration of the scrolling animation in msecs.
+                       timerInterval:     10,
+                       scrollDuration:    1000,  // Duration of the scrolling animation in msecs.
                        overshootDuration: 250,   // Duration of the overshoot animation in msecs.
                        snapbackDuration:  500,   // Duration of the snapback animation in msecs.
 
 
                        showScrollBars:    true,
                        overshootEnable:   false,
+                       outerScrollEnable: true,
+                       overflowEnable:    true,
                        scrollJump:        false,
                },
 
+               _getViewHeight: function () {
+                       return this._$view.height() + this._view_offset;
+               },
+
                _makePositioned: function ( $ele ) {
                        if ( $ele.css("position") === "static" ) {
                                $ele.css( "position", "relative" );
                },
 
                _create: function () {
-                       var $page = $('.ui-page'),
-                               direction,
+                       var direction,
                                self = this;
 
                        this._$clip = $( this.element ).addClass("ui-scrollview-clip");
-                       this._$view = this._$clip.wrapInner("<div></div>").children()
+
+                       if ( this._$clip.children(".ui-scrollview-view").length ) {
+                               this._$view = this._$clip.children(".ui-scrollview-view");
+                       } else {
+                               this._$view = this._$clip.wrapInner("<div></div>").children()
                                                        .addClass("ui-scrollview-view");
+                       }
 
                        if ( this.options.scrollMethod === "translate" ) {
                                if ( this._$view.css("transform") === undefined ) {
@@ -88,7 +98,9 @@
 
                        this._makePositioned( this._$view );
                        this._$view.css( { left: 0, top: 0 } );
-                       this._view_height = this._$view.height();
+
+                       this._view_offset = this._$view.offset().top - this._$clip.offset().top;
+                       this._view_height = this._getViewHeight();
 
                        this._sx = 0;
                        this._sy = 0;
                        this._vTracker = ( direction !== "x" ) ?
                                        new MomentumTracker( this.options ) : null;
 
-                       this._timerInterval = 1000 / this.options.fps;
+                       this._timerInterval = this.options.timerInterval;
                        this._timerID = 0;
 
                        this._timerCB = function () {
                        this._add_event();
                        this._add_scrollbar();
                        this._add_scroll_jump();
+                       this._add_overflow_indicator();
                },
 
                _startMScroll: function ( speedX, speedY ) {
 
                        this._stopMScroll();
                        this._showScrollBars();
+                       this._showOverflowIndicator();
 
                        this._$clip.trigger( this.options.startEventName );
 
                                c = this._$clip.width();
                                v = this._$view.width();
 
+                               if ( ( this._sx === 0 && speedX > 0 ) ||
+                                       ( this._sx === -(v - c) && speedX < 0 ) ) {
+                                       return;
+                               }
+
                                ht.start( this._sx, speedX,
                                        duration, (v > c) ? -(v - c) : 0, 0 );
                                keepGoing = !ht.done();
 
                        if ( vt ) {
                                c = this._$clip.height();
-                               v = this._$view.height() +
-                                       parseFloat( this._$view.css("padding-top") );
+                               v = this._getViewHeight();
+
+                               if ( ( this._sy === 0 && speedY > 0 ) ||
+                                       ( this._sy === -(v - c) && speedY < 0 ) ) {
+                                       return;
+                               }
 
                                vt.start( this._sy, speedY,
                                        duration, (v > c) ? -(v - c) : 0, 0 );
                        }
 
                        this._hideScrollBars();
+                       this._hideOverflowIndicator();
                },
 
                _handleMomentumScroll: function () {
                        var keepGoing = false,
                                x = 0,
                                y = 0,
+                               scroll_height = 0,
+                               self = this,
+                               bouncing = function ( dir ) {
+                                       setTimeout( function () {
+                                               self._bouncing_dir = dir;
+                                               self._setBouncing( self._$view, "in" );
+                                       }, 100 );
+
+                                       setTimeout( function () {
+                                               self._setBouncing( self._$view, "out" );
+                                       }, 350 );
+                               },
                                vt = this._vTracker,
                                ht = this._hTracker;
 
                                vt.update( this.options.overshootEnable );
                                y = vt.getPosition();
                                keepGoing = !vt.done();
+
+                               if ( vt.getRemained() > this.options.overshootDuration ) {
+                                       scroll_height = this._getViewHeight() - this._$clip.height();
+
+                                       if ( vt.isMin() ) {
+                                               this._outerScroll( y - vt.getRemained() / 3, scroll_height );
+
+                                               if ( scroll_height > 0 ) {
+                                                       bouncing( 1 );
+                                               }
+                                       } else if ( vt.isMax() ) {
+                                               this._outerScroll( vt.getRemained() / 3, scroll_height );
+
+                                               if ( scroll_height > 0 ) {
+                                                       bouncing( 0 );
+                                               }
+                                       }
+                               }
                        }
 
                        if ( ht ) {
                        var translate,
                                transition;
 
+                       if ( this._bouncing ) {
+                               return;
+                       }
+
                        if ( !duration || duration === undefined ) {
                                transition = "none";
                        } else {
-                               transition =  "-webkit-transform " + duration / 1000 + "s";
+                               transition =  "-webkit-transform " + duration / 1000 + "s ease-out";
                        }
 
                        if ( $.support.cssTransform3d ) {
                        });
                },
 
+               _setBouncing: function ( $ele, dir ) {
+                       if ( dir === "in" ) {
+                               if ( this._bouncing ) {
+                                       return;
+                               }
+
+                               this._bouncing = true;
+                               this._bouncing_count = 1;
+
+                               this._bouncing_org_x = 1;
+                               this._bouncing_org_y = 1;
+
+                               this._bouncing_x = 0.99;
+                               this._bouncing_y = 0.99;
+
+                               this._setOverflowIndicator( this._bouncing_dir );
+                       } else if ( dir === "out" ) {
+                               if ( !this._bouncing ) {
+                                       return;
+                               }
+
+                               this._bouncing = false;
+                               this._bouncing_count = 1;
+
+                               this._bouncing_org_x = this._bouncing_x;
+                               this._bouncing_org_y = this._bouncing_y;
+
+                               this._bouncing_x = 1;
+                               this._bouncing_y = 1;
+                               this._setOverflowIndicator( this._bouncing_dir );
+                       } else {
+                               return;
+                       }
+
+                       this._doBouncing( $ele, dir );
+               },
+
+               _doBouncing: function ( $ele, dir ) {
+                       var translate,
+                               origin,
+                               x_rate,
+                               y_rate,
+                               frame = 10,
+                               self = this;
+
+                       if ( $.support.cssTransform3d ) {
+                               translate = "translate3d(" + this._sx + "px," + this._sy + "px, 0px)";
+                       } else {
+                               translate = "translate(" + this._sx + "px," + this._sy + "px)";
+                       }
+
+                       if ( dir === "in" ) {
+                               x_rate = this._bouncing_org_x - ( this._bouncing_org_x -
+                                               this._bouncing_x ) / frame * this._bouncing_count;
+                               y_rate = this._bouncing_org_y - ( this._bouncing_org_y -
+                                               this._bouncing_y ) / frame * this._bouncing_count;
+
+                               translate += " scale(" + x_rate + "," + y_rate + ")";
+                       } else if ( dir === "out" ) {
+                               x_rate = this._bouncing_org_x + ( this._bouncing_x -
+                                               this._bouncing_org_x ) / frame * this._bouncing_count;
+                               y_rate = this._bouncing_org_y + ( this._bouncing_y -
+                                               this._bouncing_org_y ) / frame * this._bouncing_count;
+
+                               translate += " scale(" + x_rate + "," + y_rate + ")";
+                       } else {
+                               return;
+                       }
+
+                       if ( this._bouncing_dir ) {
+                               origin = "50% " + ( this._bouncing_y * 100 - 10 ) + "%";
+                       } else {
+                               origin = "50% 10%";
+                       }
+
+                       $ele.css({
+                               "-moz-transform": translate,
+                               "-webkit-transform": translate,
+                               "-ms-transform": translate,
+                               "-o-transform": translate,
+                               "transform": translate,
+                               "-webkit-transform-origin": origin,
+                       });
+
+                       this._bouncing_count++;
+
+                       if ( this._bouncing_count > frame ) {
+                               return;
+                       }
+
+                       setTimeout( function () {
+                               self._doBouncing( $ele, dir );
+                       }, this._timerInterval );
+               },
+
                _setCalibration: function ( x, y ) {
                        if ( this.options.overshootEnable ) {
                                this._sx = x;
                        }
 
                        if ( dirLock !== "x" && this._vTracker ) {
-                               scroll_height = $v.height() - $c.height() +
-                                       parseFloat( $c.css("padding-top") ) +
-                                       parseFloat( $c.css("padding-bottom") );
+                               scroll_height = this._getViewHeight() - $c.height();
 
-                               this._outerScroll( y, scroll_height );
-
-                               if ( y >= 0 ) {
+                               if ( y > 0 ) {
                                        this._sy = 0;
+
+                                       if ( scroll_height > 0 ) {
+                                               this._bouncing_dir = 0;
+                                               this._setBouncing( this._$view, "in" );
+                                       }
                                } else if ( y < -scroll_height ) {
                                        this._sy = -scroll_height;
+
+                                       if ( scroll_height > 0 ) {
+                                               this._bouncing_dir = 1;
+                                               this._setBouncing( this._$view, "in" );
+                                       }
                                } else {
                                        this._sy = y;
                                }
                                $hsb = this._$hScrollBar,
                                $sbt;
 
-                       this._setCalibration( x, y );
-
-                       if ( this._outerScrolling ) {
+                       if ( this._sx === x && this._sy === y ) {
                                return;
                        }
 
+                       this._setCalibration( x, y );
+
                        x = this._sx;
                        y = this._sy;
 
 
                                if ( sm === "translate" ) {
                                        this._setElementTransform( $sbt, "0px",
-                                               -y / $v.height() * $sbt.parent().height() + "px",
+                                               -y / this._getViewHeight() * $sbt.parent().height() + "px",
                                                duration );
                                } else {
-                                       $sbt.css( "top", -y / $v.height() * 100 + "%" );
+                                       $sbt.css( "top", -y / this._getViewHeight() * 100 + "%" );
                                }
                        }
 
 
                _outerScroll: function ( y, scroll_height ) {
                        var self = this,
-                               top = $( window ).scrollTop(),
+                               top = $( window ).scrollTop() - window.screenTop,
                                sy = 0,
                                duration = this.options.snapbackDuration,
                                start = getCurrentTime(),
                                tfunc;
 
-                       if ( this._$clip.jqmData("scroll") !== "y" ) {
+                       if ( !this.options.outerScrollEnable ) {
                                return;
                        }
 
-                       if ( this._outerScrolling ) {
+                       if ( this._$clip.jqmData("scroll") !== "y" ) {
                                return;
                        }
 
-                       if ( !this._dragging ) {
+                       if ( this._outerScrolling ) {
                                return;
                        }
 
                        }
 
                        if ( y > 0 ) {
-                               sy = -y;
+                               sy = ( window.screenTop ? window.screenTop : -y );
                        } else if ( y < -scroll_height ) {
                                sy = -y - scroll_height;
                        } else {
                                return;
                        }
 
-                       sy *= 10;
-
                        tfunc = function () {
                                var elapsed = getCurrentTime() - start;
 
                                if ( elapsed >= duration ) {
                                        window.scrollTo( 0, top + sy );
                                        self._outerScrolling = undefined;
+
+                                       self._stopMScroll();
                                } else {
-                                       ec = $.easing.easeOutQuad( elapsed / duration, elapsed, 0, 1, duration );
+                                       ec = $.easing.easeOutQuad( elapsed / duration,
+                                                       elapsed, 0, 1, duration );
 
                                        window.scrollTo( 0, top + ( sy * ec ) );
                                        self._outerScrolling = setTimeout( tfunc, self._timerInterval );
                                }
                        };
                        this._outerScrolling = setTimeout( tfunc, self._timerInterval );
-
-                       /* skip the srollview dragging */
-                       this._skip_dragging = true;
                },
 
                _scrollTo: function ( x, y, duration ) {
                                        target.is( '.ui-btn-inner' ) ||
                                        target.is( '.ui-btn-inner .ui-icon' );
 
+                       if ( this._is_button ) {
+                               if ( target.parents('.ui-slider-handle').length ) {
+                                       this._skip_dragging = true;
+                                       return;
+                               }
+                       }
+
                        /*
                         * We need to prevent the default behavior to
                         * suppress accidental selection of text, etc.
                                });
                        }
 
+                       if ( this.options.eventType === "mouse" && !this._is_inputbox && !this._is_button ) {
+                               e.preventDefault();
+                       }
+
                        this._lastX = ex;
                        this._lastY = ey;
                        this._startY = ey;
 
                _propagateDragMove: function ( sv, e, ex, ey, dir ) {
                        this._hideScrollBars();
+                       this._hideOverflowIndicator();
                        this._disableTracking();
                        sv._handleDragStart( e, ex, ey );
                        sv._directionLock = dir;
                                newY,
                                dirLock;
 
-                       if ( Math.abs( this._startY - ey ) < mt && !this._didDrag ) {
-                               return;
-                       }
-
                        this._lastMove = getCurrentTime();
 
                        if ( !this._directionLock ) {
                        }
 
                        if ( dirLock !== "x" && this._vTracker ) {
+                               if ( Math.abs( this._startY - ey ) < mt && dirLock !== "xy" ) {
+                                       return;
+                               }
+
                                y = this._sy;
                                this._speedY = dy;
                                newY = y + dy;
                        this._setScrollPosition( newX, newY );
 
                        this._showScrollBars();
+                       this._showOverflowIndicator();
                },
 
                _handleDragStop: function ( e ) {
                                y;
 
                        if ( sx || sy ) {
-                               this._startMScroll( sx, sy );
+                               if ( !this._setGestureScroll( sx, sy ) ) {
+                                       this._startMScroll( sx, sy );
+                               }
                        } else {
                                this._hideScrollBars();
+                               this._hideOverflowIndicator();
                        }
 
                        this._disableTracking();
 
+                       if ( this._bouncing ) {
+                               this._setBouncing( this._$view, "out" );
+                               this._hideScrollBars();
+                               this._hideOverflowIndicator();
+                       }
+
                        return !this._didDrag;
                },
 
+               _setGestureScroll: function ( sx, sy ) {
+                       var self = this,
+                               reset = function () {
+                                       clearTimeout( self._gesture_timer );
+                                       self._gesture_dir = 0;
+                                       self._gesture_count = 0;
+                                       self._gesture_timer = undefined;
+                               };
+
+                       if ( !sy ) {
+                               return false;
+                       }
+
+                       dir = sy > 0 ? 1 : -1;
+
+                       if ( !this._gesture_timer ) {
+                               this._gesture_count = 1;
+                               this._gesture_dir = dir;
+
+                               this._gesture_timer = setTimeout( function () {
+                                       reset();
+                               }, 1000 );
+
+                               return false;
+                       }
+
+                       if ( this._gesture_dir !== dir ) {
+                               reset();
+                               return false;
+                       }
+
+                       this._gesture_count++;
+
+                       if ( this._gesture_count === 3 ) {
+                               if ( dir > 0 ) {
+                                       this.scrollTo( 0, 0, this.options.overshootDuration );
+                               } else {
+                                       this.scrollTo( 0, -( this._getViewHeight() - this._$clip.height() ),
+                                                       this.options.overshootDuration );
+                               }
+                               reset();
+
+                               return true;
+                       }
+
+                       return false;
+               },
+
                _enableTracking: function () {
                        this._dragging = true;
                },
                        this._dragging = false;
                },
 
-               _showScrollBars: function () {
-                       var vclass = "ui-scrollbar-visible";
+               _showScrollBars: function ( interval ) {
+                       var vclass = "ui-scrollbar-visible",
+                               self = this;
 
                        if ( !this.options.showScrollBars ) {
                                return;
                        }
 
                        this._scrollbar_showed = true;
+
+                       if ( interval ) {
+                               setTimeout( function () {
+                                       self._hideScrollBars();
+                               }, interval );
+                       }
                },
 
                _hideScrollBars: function () {
                        this._scrollbar_showed = false;
                },
 
+               _resetOverflowIndicator: function () {
+                       if ( !this.options.overflowEnable || !this._overflowAvail ) {
+                               return;
+                       }
+
+                       this._overflow_top.css( "-webkit-animation", "" );
+                       this._overflow_bottom.css( "-webkit-animation", "" );
+               },
+
+               _setOverflowIndicator: function ( dir ) {
+                       if ( dir === 1 ) {
+                               this._opacity_top = "0.2";
+                               this._opacity_bottom = "0.8";
+                       } else if ( dir === 0 ) {
+                               this._opacity_top = "0.8";
+                               this._opacity_bottom = "0.2";
+                       } else {
+                               this._opacity_top = "0.5";
+                               this._opacity_bottom = "0.5";
+                       }
+               },
+
+               _getOverflowIndicator: function ( opacity ) {
+                       if ( opacity === "0.2" ) {
+                               return "-lite";
+                       } else if ( opacity === "0.8" ) {
+                               return "-dark";
+                       }
+                       return "";
+               },
+
+               _showOverflowIndicator: function () {
+                       if ( !this.options.overflowEnable || !this._overflowAvail ) {
+                               return;
+                       }
+
+                       this._overflow_top.css( "opacity", this._opacity_top );
+                       this._overflow_bottom.css( "opacity", this._opacity_bottom );
+
+                       if ( this._overflow_showed === true ) {
+                               return;
+                       }
+
+                       this._overflow_top.css( "-webkit-animation", "ui-overflow-show" +
+                                       this._getOverflowIndicator( this._opacity_top ) + " 0.3s 1 ease" );
+                       this._overflow_bottom.css( "-webkit-animation", "ui-overflow-show" +
+                                       this._getOverflowIndicator( this._opacity_bottom ) + " 0.3s 1 ease" );
+
+                       this._overflow_showed = true;
+               },
+
+               _hideOverflowIndicator: function () {
+                       var opacity_top,
+                               opacity_bottom;
+
+                       if ( !this.options.overflowEnable || !this._overflowAvail ) {
+                               return;
+                       }
+
+                       if ( this._overflow_showed === false ) {
+                               return;
+                       }
+
+                       opacity_top = this._overflow_top.css( "opacity" );
+                       opacity_bottom = this._overflow_bottom.css( "opacity" );
+
+                       this._overflow_top.css( "opacity", "0" );
+                       this._overflow_bottom.css( "opacity", "0" );
+
+                       this._overflow_top.css( "-webkit-animation", "ui-overflow-hide" +
+                                       this._getOverflowIndicator( opacity_top ) + " 0.5s 1 ease" );
+                       this._overflow_bottom.css( "-webkit-animation", "ui-overflow-hide" +
+                                       this._getOverflowIndicator( opacity_bottom ) + " 0.5s 1 ease" );
+
+                       this._overflow_showed = false;
+                       this._setOverflowIndicator();
+               },
+
                _add_event: function () {
                        var self = this,
                                $c = this._$clip,
 
                        $v.bind( this._dragEvt, this._dragCB );
 
-                       if ( $c.jqmData("scroll") !== "y" ) {
-                               return;
-                       }
-
                        $c.bind( "updatelayout", function ( e ) {
-                               var $page = $c.parentsUntil("ui-page"),
-                                       sy,
-                                       vh;
+                               var sy,
+                                       vh,
+                                       view_h = self._getViewHeight();
 
-                               if ( !$c.height() || !$v.height() ) {
+                               if ( !$c.height() || !view_h ) {
                                        self.scrollTo( 0, 0, 0 );
                                        return;
                                }
 
-                               sy = $c.height() - $v.height();
-                               vh = $v.height() - self._view_height;
+                               sy = $c.height() - view_h;
+                               vh = view_h - self._view_height;
 
-                               self._view_height = $v.height();
+                               self._view_height = view_h;
 
                                if ( vh == 0 || vh > $c.height() / 2 ) {
                                        return;
                                }
 
                                if ( self._sy - sy <= -vh ) {
-                                       self.scrollTo( 0, self._sy,
+                                       self.scrollTo( 0, sy,
                                                self.options.snapbackDuration );
                                } else if ( self._sy - sy <= vh + self.options.moveThreshold ) {
                                        self.scrollTo( 0, sy,
                        });
 
                        $( window ).bind( "resize", function ( e ) {
-                               var $page = $c.parentsUntil("ui-page"),
-                                       focused;
+                               var focused,
+                                       view_h = self._getViewHeight();
+
+                               if ( $(".ui-page-active").get(0) !== $c.closest(".ui-page").get(0) ) {
+                                       return;
+                               }
 
-                               if ( !$c.height() || !$v.height() ) {
+                               if ( !$c.height() || !view_h ) {
                                        return;
                                }
 
                                        focused.trigger("resize.scrollview");
                                }
 
-                               /* calibration */
-                               if ( self._sy < $c.height() - $v.height() ) {
-                                       self.scrollTo( 0, self._sy,
-                                               self.options.snapbackDuration );
-                               }
+                               /* calibration - after triggered throttledresize */
+                               setTimeout( function () {
+                                       if ( self._sy < $c.height() - self._getViewHeight() ) {
+                                               self.scrollTo( 0, self._sy,
+                                                       self.options.snapbackDuration );
+                                       }
+                               }, 260 );
 
-                               self._view_height = $v.height();
+                               self._view_height = view_h;
                        });
+
+                       $c.closest(".ui-page")
+                               .one( "pageshow", function ( e ) {
+                                       self._view_offset = self._$view.offset().top - self._$clip.offset().top;
+                                       self._view_height = self._getViewHeight();
+                               })
+                               .bind( "pageshow", function ( e ) {
+                                       /* should be called after pagelayout */
+                                       setTimeout( function () {
+                                               self._set_scrollbar_size();
+                                               self._setScrollPosition( self._sx, self._sy );
+                                               self._showScrollBars( 2000 );
+                                               self._resetOverflowIndicator();
+                                       }, 0 );
+                               });
                },
 
                _add_scrollbar: function () {
                        }
 
                        if ( this._vTracker ) {
-                               top_btn = $( '<div class="ui-scroll-jump-top-bg ui-btn" data-theme="s">' +
-                                               '<div class="ui-scroll-jump-top"></div></div>' );
-                               $c.append( top_btn );
+                               top_btn = $( '<div class="ui-scroll-jump-top-bg">' +
+                                               '<div data-role="button" data-inline="true" data-icon="jumptop" style="width:37px;height:37px">.</div></div>' );
+                               $c.append( top_btn ).trigger("create");
 
                                top_btn.bind( "vclick", function () {
                                        self.scrollTo( 0, 0, self.options.overshootDuration );
                        }
 
                        if ( this._hTracker ) {
-                               left_btn = $( '<div class="ui-scroll-jump-left-bg ui-btn" data-theme="s">' +
-                                               '<div class="ui-scroll-jump-left"></div></div>' );
-                               $c.append( left_btn );
+                               left_btn = $( '<div class="ui-scroll-jump-left-bg">' +
+                                               '<div data-role="button" data-inline="true" data-icon="jumpleft" style="width:37px;height:37px">.</div></div>' );
+                               $c.append( left_btn ).trigger("create");
 
                                left_btn.bind( "vclick", function () {
                                        self.scrollTo( 0, 0, self.options.overshootDuration );
                        }
                },
 
+               _add_overflow_indicator: function () {
+                       if ( !this.options.overflowEnable ) {
+                               return;
+                       }
+
+                       this._overflow_top = $( '<div class="ui-overflow-indicator-top"></div>' );
+                       this._overflow_bottom = $( '<div class="ui-overflow-indicator-bottom"></div>' );
+
+                       this._$clip.append( this._overflow_top );
+                       this._$clip.append( this._overflow_bottom );
+
+                       this._opacity_top = "0.5";
+                       this._opacity_bottom = "0.5";
+                       this._overflow_showed = false;
+               },
+
                _set_scrollbar_size: function () {
                        var $c = this._$clip,
                                $v = this._$view,
                                }
                                if ( this._$hScrollBar && vw ) {
                                        thumb = this._$hScrollBar.find(".ui-scrollbar-thumb");
-                                       thumb.css( "width", (cw >= vw ? "100%" :
+                                       thumb.css( "width", (cw >= vw ? "0" :
                                                        (Math.floor(cw / vw * 100) || 1) + "%") );
                                }
                        }
 
                        if ( this._vTracker ) {
                                ch = $c.height();
-                               vh = $v.height();
+                               vh = this._getViewHeight();
                                this._maxY = ch - vh;
 
                                if ( this._maxY > 0 ) {
                                }
                                if ( this._$vScrollBar && vh ) {
                                        thumb = this._$vScrollBar.find(".ui-scrollbar-thumb");
-                                       thumb.css( "height", (ch >= vh ? "100%" :
+                                       thumb.css( "height", (ch >= vh ? "0" :
                                                        (Math.floor(ch / vh * 100) || 1) + "%") );
+
+                                       this._overflowAvail = !!thumb.height();
                                }
                        }
                }
                        this.minPos = 0;
                        this.maxPos = 0;
                        this.duration = 0;
+                       this.remained = 0;
                },
 
                update: function ( overshootEnable ) {
 
                        elapsed = elapsed > duration ? duration : elapsed;
 
+                       this.remained = duration - elapsed;
+
                        if ( state === tstates.scrolling || state === tstates.overshot ) {
                                dx = this.speed *
                                        ( 1 - $.easing[this.easing]( elapsed / duration,
                                this.pos = x;
 
                                if ( state === tstates.overshot ) {
+                                       if ( !overshootEnable ) {
+                                               this.state = tstates.done;
+                                       }
                                        if ( elapsed >= duration ) {
                                                this.state = tstates.snapback;
                                                this.fromPos = this.pos;
                        return this.state === tstates.done;
                },
 
+               isMin: function () {
+                       return this.pos === this.minPos;
+               },
+
+               isMax: function () {
+                       return this.pos === this.maxPos;
+               },
+
+               getRemained: function () {
+                       return this.remained;
+               },
+
                getPosition: function () {
                        return this.pos;
                }
                                $( this ).scrolllistview();
                        } else {
                                var st = $( this ).jqmData("scroll"),
-                                       dir = st && ( st.search(/^[xy]/) !== -1 ) ? st.charAt(0) : null,
+                                       dir = st && ( st.search(/^[xy]/) !== -1 ) ? st : null,
+                                       content = $(this).hasClass("ui-content"),
                                        opts;
 
                                if ( st === "none" ) {
 
                                opts = {
                                        direction: dir || undefined,
+                                       overflowEnable: content,
                                        scrollMethod: $( this ).jqmData("scroll-method") || undefined,
                                        scrollJump: $( this ).jqmData("scroll-jump") || undefined
                                };