showScrollBars: true,
overshootEnable: false,
outerScrollEnable: true,
+ overflowEnable: true,
scrollJump: false,
},
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 ) {
this._view_offset = this._$view.offset().top - this._$clip.offset().top;
this._view_height = this._getViewHeight();
- this._clip_height = this._$clip.height();
this._sx = 0;
this._sy = 0;
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 )) &&
+ v > c ) {
+ 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;
+ c = this._$clip.height();
+ v = this._getViewHeight();
+
+ if ( (( this._sy === 0 && speedY > 0 ) ||
+ ( this._sy === -(v - c) && speedY < 0 )) &&
+ v > c ) {
+ return;
+ }
vt.start( this._sy, speedY,
duration, (v > c) ? -(v - c) : 0, 0 );
}
this._hideScrollBars();
+ this._hideOverflowIndicator();
},
_handleMomentumScroll: function () {
x = 0,
y = 0,
scroll_height = 0,
+ self = this,
+ end_effect = function ( dir ) {
+ setTimeout( function () {
+ self._effect_dir = dir;
+ self._setEndEffect( "in" );
+ }, 100 );
+
+ setTimeout( function () {
+ self._setEndEffect( "out" );
+ }, 350 );
+ },
vt = this._vTracker,
ht = this._hTracker;
keepGoing = !vt.done();
if ( vt.getRemained() > this.options.overshootDuration ) {
- scroll_height = this._view_height - this._clip_height;
-
- if ( vt.isMin() ) {
+ scroll_height = this._getViewHeight() - this._$clip.height();
+
+ if ( !vt.isAvail() ) {
+ if ( this._speedY > 0 ) {
+ this._outerScroll( vt.getRemained() / 3, scroll_height );
+ } else {
+ this._outerScroll( y - vt.getRemained() / 3, scroll_height );
+ }
+ } else if ( vt.isMin() ) {
this._outerScroll( y - vt.getRemained() / 3, scroll_height );
+
+ if ( scroll_height > 0 ) {
+ end_effect( 1 );
+ }
} else if ( vt.isMax() ) {
this._outerScroll( vt.getRemained() / 3, scroll_height );
+
+ if ( scroll_height > 0 ) {
+ end_effect( 0 );
+ }
}
}
}
var translate,
transition;
+ if ( this._endEffect ) {
+ return;
+ }
+
if ( !duration || duration === undefined ) {
transition = "none";
} else {
});
},
+ _setEndEffect: function ( dir ) {
+ var scroll_height = this._getViewHeight() - this._$clip.height();
+
+ if ( this._softkeyboard ) {
+ if ( this._effect_dir ) {
+ this._outerScroll( -scroll_height - this._softkeyboardHeight,
+ scroll_height );
+ } else {
+ this._outerScroll( this._softkeyboardHeight, scroll_height );
+ }
+ return;
+ }
+
+ if ( dir === "in" ) {
+ if ( this._endEffect ) {
+ return;
+ }
+
+ this._endEffect = true;
+ this._setOverflowIndicator( this._effect_dir );
+ } else if ( dir === "out" ) {
+ if ( !this._endEffect ) {
+ return;
+ }
+
+ this._endEffect = false;
+ this._setOverflowIndicator( this._effect_dir );
+ }
+ },
+
_setCalibration: function ( x, y ) {
if ( this.options.overshootEnable ) {
this._sx = x;
}
if ( dirLock !== "x" && this._vTracker ) {
- scroll_height = this._view_height - this._clip_height;
+ scroll_height = this._getViewHeight() - $c.height();
if ( y > 0 ) {
this._sy = 0;
+
+ if ( this._didDrag && scroll_height > 0 ) {
+ this._effect_dir = 0;
+ this._setEndEffect( "in" );
+ }
} else if ( y < -scroll_height ) {
this._sy = -scroll_height;
+
+ if ( this._didDrag && scroll_height > 0 ) {
+ this._effect_dir = 1;
+ this._setEndEffect( "in" );
+ }
} else {
+ if ( this._endEffect && this._sy !== y ) {
+ this._endEffect = false;
+ this._setOverflowIndicator();
+ }
+
this._sy = y;
}
if ( sm === "translate" ) {
this._setElementTransform( $sbt, "0px",
- -y / this._view_height * $sbt.parent().height() + "px",
+ -y / this._getViewHeight() * $sbt.parent().height() + "px",
duration );
} else {
- $sbt.css( "top", -y / this._view_height * 100 + "%" );
+ $sbt.css( "top", -y / this._getViewHeight() * 100 + "%" );
}
}
return;
}
- if ( scroll_height < 0 ) {
- return;
- }
-
if ( y > 0 ) {
- sy = -y;
+ sy = ( window.screenTop ? window.screenTop : -y );
} else if ( y < -scroll_height ) {
sy = -y - scroll_height;
} else {
if ( this._is_inputbox ) {
target.one( "resize.scrollview", function () {
- if ( ey > self._clip_height ) {
- self.scrollTo( -ex, self._sy - ey + self._clip_height,
+ if ( ey > $c.height() ) {
+ self.scrollTo( -ex, self._sy - ey + $c.height(),
self.options.snapbackDuration );
}
});
_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._endEffect ) {
+ this._setEndEffect( "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._scrollbar_showed = false;
},
+ _resetOverflowIndicator: function () {
+ if ( !this.options.overflowEnable || !this._overflowAvail || this._softkeyboard ) {
+ 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 || this._softkeyboard ) {
+ 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 || this._softkeyboard ) {
+ 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" ) {
+ $v.bind( "keydown", function ( e ) {
+ var elem,
+ elem_top,
+ screen_h;
+
+ if ( e.keyCode == 9 ) {
+ return false;
+ }
+
+ elem = $c.find(".ui-focus");
+
+ if ( elem === undefined ) {
+ return;
+ }
+
+ elem_top = elem.offset().top;
+ screen_h = $c.offset().top + $c.height() - elem.height();
+
+ if ( self._softkeyboard ) {
+ screen_h -= self._softkeyboardHeight;
+ }
+
+ if ( ( elem_top < 0 ) || ( elem_top > screen_h ) ) {
+ self.scrollTo( 0, self._sy - elem_top +
+ elem.height() + $c.offset().top, 0);
+ }
+
return;
- }
+ });
+
+ $v.bind( "keyup", function ( e ) {
+ var input,
+ elem,
+ elem_top,
+ screen_h;
+
+ if ( e.keyCode != 9 ) {
+ return;
+ }
+
+ /* Tab Key */
+
+ input = $( this ).find(":input");
+
+ for ( i = 0; i < input.length; i++ ) {
+ if ( !$( input[i] ).hasClass("ui-focus") ) {
+ continue;
+ }
+
+ if ( i + 1 == input.length ) {
+ elem = $( input[0] );
+ } else {
+ elem = $( input[i + 1] );
+ }
+
+ elem_top = elem.offset().top;
+ screen_h = $c.offset().top + $c.height() - elem.height();
+
+ if ( self._softkeyboard ) {
+ screen_h -= self._softkeyboardHeight;
+ }
+
+ if ( ( elem_top < 0 ) || ( elem_top > screen_h ) ) {
+ self.scrollTo( 0, self._sy - elem_top +
+ elem.height() + $c.offset().top, 0);
+ }
+
+ elem.focus();
+
+ break;
+ }
+
+ return false;
+ });
$c.bind( "updatelayout", function ( e ) {
var sy,
vh,
- clip_h = $c.height(),
view_h = self._getViewHeight();
- if ( !clip_h || !view_h ) {
+ if ( !$c.height() || !view_h ) {
self.scrollTo( 0, 0, 0 );
return;
}
- sy = clip_h - view_h;
+ sy = $c.height() - view_h;
vh = view_h - self._view_height;
self._view_height = view_h;
- self._clip_height = clip_h;
- if ( vh == 0 || vh > clip_h / 2 ) {
+ if ( vh == 0 || vh > $c.height() / 2 ) {
return;
}
- if ( self._sy - sy <= -vh ) {
+ if ( sy > 0 ) {
+ self.scrollTo( 0, 0, 0 );
+ } else if ( self._sy - sy <= -vh ) {
self.scrollTo( 0, self._sy,
self.options.snapbackDuration );
} else if ( self._sy - sy <= vh + self.options.moveThreshold ) {
$( window ).bind( "resize", function ( e ) {
var focused,
- clip_h = $c.height(),
view_h = self._getViewHeight();
if ( $(".ui-page-active").get(0) !== $c.closest(".ui-page").get(0) ) {
return;
}
- if ( !clip_h || !view_h ) {
+ if ( !$c.height() || !view_h ) {
return;
}
/* calibration - after triggered throttledresize */
setTimeout( function () {
- self._view_height = self._getViewHeight();
- self._clip_height = $c.height();
-
- if ( self._sy < self._clip_height - self._veiw_height ) {
- self.scrollTo( 0, self._sy,
- self.options.snapbackDuration );
+ if ( self._sy < $c.height() - self._getViewHeight() ) {
+ self.scrollTo( 0, $c.height() - self._getViewHeight(),
+ self.options.overshootDuration );
}
}, 260 );
self._view_height = view_h;
- self._clip_height = clip_h;
+ });
+
+ $( window ).bind( "vmouseout", function ( e ) {
+ var drag_stop = false;
+
+ if ( $(".ui-page-active").get(0) !== $c.closest(".ui-page").get(0) ) {
+ return;
+ }
+
+ if ( !self._dragging ) {
+ return;
+ }
+
+ if ( e.pageX < 0 || e.pageX > $( window ).width() ) {
+ drag_stop = true;
+ }
+
+ if ( e.pageY < 0 || e.pageY > $( window ).height() ) {
+ drag_stop = true;
+ }
+
+ if ( drag_stop ) {
+ self._hideScrollBars();
+ self._hideOverflowIndicator();
+ self._disableTracking();
+ }
+ });
+
+ this._softkeyboard = false;
+ this._softkeyboardHeight = 0;
+
+ window.addEventListener( "softkeyboardchange", function ( e ) {
+ if ( $(".ui-page-active").get(0) !== $c.closest(".ui-page").get(0) ) {
+ return;
+ }
+
+ self._softkeyboard = ( e.state === "on" ? true : false );
+ self._softkeyboardHeight = e.height;
});
$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._view_height = self._getViewHeight();
- self._clip_height = self._$clip.height();
-
self._set_scrollbar_size();
self._setScrollPosition( self._sx, self._sy );
self._showScrollBars( 2000 );
+ self._resetOverflowIndicator();
}, 0 );
});
},
}
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._vTracker ) {
- ch = this._clip_height;
- vh = this._view_height;
+ ch = $c.height();
+ vh = this._getViewHeight();
this._maxY = ch - vh;
if ( this._maxY > 0 ) {
thumb = this._$vScrollBar.find(".ui-scrollbar-thumb");
thumb.css( "height", (ch >= vh ? "0" :
(Math.floor(ch / vh * 100) || 1) + "%") );
+
+ this._overflowAvail = !!thumb.height();
}
}
}
return this.pos === this.maxPos;
},
+ isAvail: function () {
+ return !( this.minPos === this.maxPos );
+ },
+
getRemained: function () {
return this.remained;
},
$( 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
};