2 * jQuery Mobile Framework : scrollview plugin
3 * Copyright (c) 2010 Adobe Systems Incorporated - Kin Blas (jblas@adobe.com)
4 * Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
5 * Note: Code is in draft form and is subject to change
6 * Modified by Koeun Choi <koeun.choi@samsung.com>
7 * Modified by Minkyu Kang <mk7.kang@samsung.com>
10 (function ( $, window, document, undefined ) {
12 function resizePageContentHeight( page ) {
13 var $page = $( page ),
14 $content = $page.children(".ui-content"),
15 hh = $page.children(".ui-header").outerHeight() || 0,
16 fh = $page.children(".ui-footer").outerHeight() || 0,
17 pt = parseFloat( $content.css("padding-top") ),
18 pb = parseFloat( $content.css("padding-bottom") ),
19 wh = $( window ).height();
21 $content.height( wh - (hh + fh) - (pt + pb) );
24 function MomentumTracker( options ) {
25 this.options = $.extend( {}, options );
26 this.easing = "easeOutQuad";
37 function getCurrentTime() {
41 jQuery.widget( "tizen.scrollview", jQuery.mobile.widget, {
43 direction: null, // "x", "y", or null for both.
46 scrollDuration: 1000, // Duration of the scrolling animation in msecs.
47 overshootDuration: 250, // Duration of the overshoot animation in msecs.
48 snapbackDuration: 500, // Duration of the snapback animation in msecs.
50 moveThreshold: 30, // User must move this many pixels in any direction to trigger a scroll.
51 moveIntervalThreshold: 150, // Time between mousemoves must not exceed this threshold.
53 scrollMethod: "translate", // "translate", "position"
54 startEventName: "scrollstart",
55 updateEventName: "scrollupdate",
56 stopEventName: "scrollstop",
58 eventType: $.support.touch ? "touch" : "mouse",
61 overshootEnable: false,
62 outerScrollEnable: true,
67 _getViewHeight: function () {
68 return this._$view.height() + this._view_offset;
71 _makePositioned: function ( $ele ) {
72 if ( $ele.css("position") === "static" ) {
73 $ele.css( "position", "relative" );
77 _create: function () {
81 this._$clip = $( this.element ).addClass("ui-scrollview-clip");
83 if ( this._$clip.children(".ui-scrollview-view").length ) {
84 this._$view = this._$clip.children(".ui-scrollview-view");
86 this._$view = this._$clip.wrapInner("<div></div>").children()
87 .addClass("ui-scrollview-view");
90 if ( this.options.scrollMethod === "translate" ) {
91 if ( this._$view.css("transform") === undefined ) {
92 this.options.scrollMethod = "position";
96 this._$clip.css( "overflow", "hidden" );
97 this._makePositioned( this._$clip );
99 this._makePositioned( this._$view );
100 this._$view.css( { left: 0, top: 0 } );
102 this._view_offset = this._$view.offset().top - this._$clip.offset().top;
103 this._view_height = this._getViewHeight();
108 direction = this.options.direction;
110 this._hTracker = ( direction !== "y" ) ?
111 new MomentumTracker( this.options ) : null;
112 this._vTracker = ( direction !== "x" ) ?
113 new MomentumTracker( this.options ) : null;
115 this._timerInterval = this.options.timerInterval;
118 this._timerCB = function () {
119 self._handleMomentumScroll();
123 this._add_scrollbar();
124 this._add_scroll_jump();
125 this._add_overflow_indicator();
128 _startMScroll: function ( speedX, speedY ) {
129 var keepGoing = false,
130 duration = this.options.scrollDuration,
137 this._showScrollBars();
138 this._showOverflowIndicator();
140 this._$clip.trigger( this.options.startEventName );
143 c = this._$clip.width();
144 v = this._$view.width();
146 if ( (( this._sx === 0 && speedX > 0 ) ||
147 ( this._sx === -(v - c) && speedX < 0 )) &&
152 ht.start( this._sx, speedX,
153 duration, (v > c) ? -(v - c) : 0, 0 );
154 keepGoing = !ht.done();
158 c = this._$clip.height();
159 v = this._getViewHeight();
161 if ( (( this._sy === 0 && speedY > 0 ) ||
162 ( this._sy === -(v - c) && speedY < 0 )) &&
167 vt.start( this._sy, speedY,
168 duration, (v > c) ? -(v - c) : 0, 0 );
169 keepGoing = keepGoing || !vt.done();
173 this._timerID = setTimeout( this._timerCB, this._timerInterval );
179 _stopMScroll: function () {
180 if ( this._timerID ) {
181 this._$clip.trigger( this.options.stopEventName );
182 clearTimeout( this._timerID );
186 if ( this._vTracker ) {
187 this._vTracker.reset();
190 if ( this._hTracker ) {
191 this._hTracker.reset();
194 this._hideScrollBars();
195 this._hideOverflowIndicator();
198 _handleMomentumScroll: function () {
199 var keepGoing = false,
204 end_effect = function ( dir ) {
205 setTimeout( function () {
206 self._effect_dir = dir;
207 self._setEndEffect( "in" );
210 setTimeout( function () {
211 self._setEndEffect( "out" );
217 if ( this._outerScrolling ) {
222 vt.update( this.options.overshootEnable );
223 y = vt.getPosition();
224 keepGoing = !vt.done();
226 if ( vt.getRemained() > this.options.overshootDuration ) {
227 scroll_height = this._getViewHeight() - this._$clip.height();
229 if ( !vt.isAvail() ) {
230 if ( this._speedY > 0 ) {
231 this._outerScroll( vt.getRemained() / 3, scroll_height );
233 this._outerScroll( y - vt.getRemained() / 3, scroll_height );
235 } else if ( vt.isMin() ) {
236 this._outerScroll( y - vt.getRemained() / 3, scroll_height );
238 if ( scroll_height > 0 ) {
241 } else if ( vt.isMax() ) {
242 this._outerScroll( vt.getRemained() / 3, scroll_height );
244 if ( scroll_height > 0 ) {
252 ht.update( this.options.overshootEnable );
253 x = ht.getPosition();
254 keepGoing = keepGoing || !ht.done();
257 this._setScrollPosition( x, y );
258 this._$clip.trigger( this.options.updateEventName,
259 [ { x: x, y: y } ] );
262 this._timerID = setTimeout( this._timerCB, this._timerInterval );
268 _setElementTransform: function ( $ele, x, y, duration ) {
272 if ( this._endEffect ) {
276 if ( !duration || duration === undefined ) {
279 transition = "-webkit-transform " + duration / 1000 + "s ease-out";
282 if ( $.support.cssTransform3d ) {
283 translate = "translate3d(" + x + "," + y + ", 0px)";
285 translate = "translate(" + x + "," + y + ")";
289 "-moz-transform": translate,
290 "-webkit-transform": translate,
291 "-ms-transform": translate,
292 "-o-transform": translate,
293 "transform": translate,
294 "-webkit-transition": transition
298 _setEndEffect: function ( dir ) {
299 var scroll_height = this._getViewHeight() - this._$clip.height();
301 if ( this._softkeyboard ) {
302 if ( this._effect_dir ) {
303 this._outerScroll( -scroll_height - this._softkeyboardHeight,
306 this._outerScroll( this._softkeyboardHeight, scroll_height );
311 if ( dir === "in" ) {
312 if ( this._endEffect ) {
316 this._endEffect = true;
317 this._setOverflowIndicator( this._effect_dir );
318 } else if ( dir === "out" ) {
319 if ( !this._endEffect ) {
323 this._endEffect = false;
324 this._setOverflowIndicator( this._effect_dir );
328 _setCalibration: function ( x, y ) {
329 if ( this.options.overshootEnable ) {
335 var $v = this._$view,
337 dirLock = this._directionLock,
341 if ( dirLock !== "y" && this._hTracker ) {
342 scroll_width = $v.width() - $c.width();
346 } else if ( x < -scroll_width ) {
347 this._sx = -scroll_width;
352 if ( scroll_width < 0 ) {
357 if ( dirLock !== "x" && this._vTracker ) {
358 scroll_height = this._getViewHeight() - $c.height();
363 if ( this._didDrag && scroll_height > 0 ) {
364 this._effect_dir = 0;
365 this._setEndEffect( "in" );
367 } else if ( y < -scroll_height ) {
368 this._sy = -scroll_height;
370 if ( this._didDrag && scroll_height > 0 ) {
371 this._effect_dir = 1;
372 this._setEndEffect( "in" );
375 if ( this._endEffect && this._sy !== y ) {
376 this._endEffect = false;
377 this._setOverflowIndicator();
383 if ( scroll_height < 0 ) {
389 _setScrollPosition: function ( x, y, duration ) {
390 var $v = this._$view,
391 sm = this.options.scrollMethod,
392 $vsb = this._$vScrollBar,
393 $hsb = this._$hScrollBar,
396 this._setCalibration( x, y );
401 if ( sm === "translate" ) {
402 this._setElementTransform( $v, x + "px", y + "px", duration );
404 $v.css( {left: x + "px", top: y + "px"} );
408 $sbt = $vsb.find(".ui-scrollbar-thumb");
410 if ( sm === "translate" ) {
411 this._setElementTransform( $sbt, "0px",
412 -y / this._getViewHeight() * $sbt.parent().height() + "px",
415 $sbt.css( "top", -y / this._getViewHeight() * 100 + "%" );
420 $sbt = $hsb.find(".ui-scrollbar-thumb");
422 if ( sm === "translate" ) {
423 this._setElementTransform( $sbt,
424 -x / $v.width() * $sbt.parent().width() + "px", "0px",
427 $sbt.css("left", -x / $v.width() * 100 + "%");
432 _outerScroll: function ( y, scroll_height ) {
434 top = $( window ).scrollTop() - window.screenTop,
436 duration = this.options.snapbackDuration,
437 start = getCurrentTime(),
440 if ( !this.options.outerScrollEnable ) {
444 if ( this._$clip.jqmData("scroll") !== "y" ) {
448 if ( this._outerScrolling ) {
453 sy = ( window.screenTop ? window.screenTop : -y );
454 } else if ( y < -scroll_height ) {
455 sy = -y - scroll_height;
460 tfunc = function () {
461 var elapsed = getCurrentTime() - start;
463 if ( elapsed >= duration ) {
464 window.scrollTo( 0, top + sy );
465 self._outerScrolling = undefined;
469 ec = $.easing.easeOutQuad( elapsed / duration,
470 elapsed, 0, 1, duration );
472 window.scrollTo( 0, top + ( sy * ec ) );
473 self._outerScrolling = setTimeout( tfunc, self._timerInterval );
476 this._outerScrolling = setTimeout( tfunc, self._timerInterval );
479 _scrollTo: function ( x, y, duration ) {
481 start = getCurrentTime(),
482 efunc = $.easing.easeOutQuad,
492 tfunc = function () {
493 var elapsed = getCurrentTime() - start,
496 if ( elapsed >= duration ) {
498 self._setScrollPosition( x, y );
500 ec = efunc( elapsed / duration, elapsed, 0, 1, duration );
502 self._setScrollPosition( sx + ( dx * ec ), sy + ( dy * ec ) );
503 self._timerID = setTimeout( tfunc, self._timerInterval );
507 this._timerID = setTimeout( tfunc, this._timerInterval );
510 scrollTo: function ( x, y, duration ) {
513 if ( !duration || this.options.scrollMethod === "translate" ) {
514 this._setScrollPosition( x, y, duration );
516 this._scrollTo( x, y, duration );
520 getScrollPosition: function () {
521 return { x: -this._sx, y: -this._sy };
524 _getScrollHierarchy: function () {
528 this._$clip.parents( ".ui-scrollview-clip").each( function () {
529 d = $( this ).jqmData("scrollview");
537 _getAncestorByDirection: function ( dir ) {
538 var svh = this._getScrollHierarchy(),
545 svdir = sv.options.direction;
547 if (!svdir || svdir === dir) {
554 _handleDragStart: function ( e, ex, ey ) {
557 this._didDrag = false;
558 this._skip_dragging = false;
560 var target = $( e.target ),
563 svdir = this.options.direction;
565 /* should prevent the default behavior when click the button */
566 this._is_button = target.is( '.ui-btn-text' ) ||
567 target.is( '.ui-btn-inner' ) ||
568 target.is( '.ui-btn-inner .ui-icon' );
570 if ( this._is_button ) {
571 if ( target.parents('.ui-slider-handle').length ) {
572 this._skip_dragging = true;
578 * We need to prevent the default behavior to
579 * suppress accidental selection of text, etc.
581 this._is_inputbox = target.is(':input') ||
582 target.parents(':input').length > 0;
584 if ( this._is_inputbox ) {
585 target.one( "resize.scrollview", function () {
586 if ( ey > $c.height() ) {
587 self.scrollTo( -ex, self._sy - ey + $c.height(),
588 self.options.snapbackDuration );
593 if ( this.options.eventType === "mouse" && !this._is_inputbox && !this._is_button ) {
600 this._doSnapBackX = false;
601 this._doSnapBackY = false;
604 this._directionLock = "";
607 this._enableTracking();
609 this._set_scrollbar_size();
612 _propagateDragMove: function ( sv, e, ex, ey, dir ) {
613 this._hideScrollBars();
614 this._hideOverflowIndicator();
615 this._disableTracking();
616 sv._handleDragStart( e, ex, ey );
617 sv._directionLock = dir;
618 sv._didDrag = this._didDrag;
621 _handleDragMove: function ( e, ex, ey ) {
622 if ( this._skip_dragging ) {
626 if ( !this._dragging ) {
630 if ( !this._is_inputbox && !this._is_button ) {
634 var mt = this.options.moveThreshold,
635 dx = ex - this._lastX,
636 dy = ey - this._lastY,
637 svdir = this.options.direction,
647 this._lastMove = getCurrentTime();
649 if ( !this._directionLock ) {
653 if ( x < mt && y < mt ) {
657 if ( x < y && (x / y) < 0.5 ) {
659 } else if ( x > y && (y / x) < 0.5 ) {
663 if ( svdir && dir && svdir !== dir ) {
665 * This scrollview can't handle the direction the user
666 * is attempting to scroll. Find an ancestor scrollview
667 * that can handle the request.
670 sv = this._getAncestorByDirection( dir );
672 this._propagateDragMove( sv, e, ex, ey, dir );
677 this._directionLock = svdir || (dir || "none");
682 dirLock = this._directionLock;
684 if ( dirLock !== "y" && this._hTracker ) {
689 this._doSnapBackX = false;
691 scope = ( newX > 0 || newX < this._maxX );
693 if ( scope && dirLock === "x" ) {
694 sv = this._getAncestorByDirection("x");
696 this._setScrollPosition( newX > 0 ?
697 0 : this._maxX, newY );
698 this._propagateDragMove( sv, e, ex, ey, dir );
702 newX = x + ( dx / 2 );
703 this._doSnapBackX = true;
707 if ( dirLock !== "x" && this._vTracker ) {
708 if ( Math.abs( this._startY - ey ) < mt && dirLock !== "xy" ) {
716 this._doSnapBackY = false;
718 scope = ( newY > 0 || newY < this._maxY );
720 if ( scope && dirLock === "y" ) {
721 sv = this._getAncestorByDirection("y");
723 this._setScrollPosition( newX,
724 newY > 0 ? 0 : this._maxY );
725 this._propagateDragMove( sv, e, ex, ey, dir );
729 newY = y + ( dy / 2 );
730 this._doSnapBackY = true;
734 if ( this.options.overshootEnable === false ) {
735 this._doSnapBackX = false;
736 this._doSnapBackY = false;
739 this._didDrag = true;
743 this._setScrollPosition( newX, newY );
745 this._showScrollBars();
746 this._showOverflowIndicator();
749 _handleDragStop: function ( e ) {
750 if ( this._skip_dragging ) {
754 var l = this._lastMove,
755 t = getCurrentTime(),
756 doScroll = (l && (t - l) <= this.options.moveIntervalThreshold),
757 sx = ( this._hTracker && this._speedX && doScroll ) ?
758 this._speedX : ( this._doSnapBackX ? 1 : 0 ),
759 sy = ( this._vTracker && this._speedY && doScroll ) ?
760 this._speedY : ( this._doSnapBackY ? 1 : 0 ),
761 svdir = this.options.direction,
766 if ( !this._setGestureScroll( sx, sy ) ) {
767 this._startMScroll( sx, sy );
770 this._hideScrollBars();
771 this._hideOverflowIndicator();
774 this._disableTracking();
776 if ( this._endEffect ) {
777 this._setEndEffect( "out" );
778 this._hideScrollBars();
779 this._hideOverflowIndicator();
782 return !this._didDrag;
785 _setGestureScroll: function ( sx, sy ) {
787 reset = function () {
788 clearTimeout( self._gesture_timer );
789 self._gesture_dir = 0;
790 self._gesture_count = 0;
791 self._gesture_timer = undefined;
798 dir = sy > 0 ? 1 : -1;
800 if ( !this._gesture_timer ) {
801 this._gesture_count = 1;
802 this._gesture_dir = dir;
804 this._gesture_timer = setTimeout( function () {
811 if ( this._gesture_dir !== dir ) {
816 this._gesture_count++;
818 if ( this._gesture_count === 3 ) {
820 this.scrollTo( 0, 0, this.options.overshootDuration );
822 this.scrollTo( 0, -( this._getViewHeight() - this._$clip.height() ),
823 this.options.overshootDuration );
833 _enableTracking: function () {
834 this._dragging = true;
837 _disableTracking: function () {
838 this._dragging = false;
841 _showScrollBars: function ( interval ) {
842 var vclass = "ui-scrollbar-visible",
845 if ( !this.options.showScrollBars ) {
848 if ( this._scrollbar_showed ) {
852 if ( this._$vScrollBar ) {
853 this._$vScrollBar.addClass( vclass );
855 if ( this._$hScrollBar ) {
856 this._$hScrollBar.addClass( vclass );
859 this._scrollbar_showed = true;
862 setTimeout( function () {
863 self._hideScrollBars();
868 _hideScrollBars: function () {
869 var vclass = "ui-scrollbar-visible";
871 if ( !this.options.showScrollBars ) {
874 if ( !this._scrollbar_showed ) {
878 if ( this._$vScrollBar ) {
879 this._$vScrollBar.removeClass( vclass );
881 if ( this._$hScrollBar ) {
882 this._$hScrollBar.removeClass( vclass );
885 this._scrollbar_showed = false;
888 _resetOverflowIndicator: function () {
889 if ( !this.options.overflowEnable || !this._overflowAvail || this._softkeyboard ) {
893 this._overflow_top.css( "-webkit-animation", "" );
894 this._overflow_bottom.css( "-webkit-animation", "" );
897 _setOverflowIndicator: function ( dir ) {
899 this._opacity_top = "0.2";
900 this._opacity_bottom = "0.8";
901 } else if ( dir === 0 ) {
902 this._opacity_top = "0.8";
903 this._opacity_bottom = "0.2";
905 this._opacity_top = "0.5";
906 this._opacity_bottom = "0.5";
910 _getOverflowIndicator: function ( opacity ) {
911 if ( opacity === "0.2" ) {
913 } else if ( opacity === "0.8" ) {
919 _showOverflowIndicator: function () {
920 if ( !this.options.overflowEnable || !this._overflowAvail || this._softkeyboard ) {
924 this._overflow_top.css( "opacity", this._opacity_top );
925 this._overflow_bottom.css( "opacity", this._opacity_bottom );
927 if ( this._overflow_showed === true ) {
931 this._overflow_top.css( "-webkit-animation", "ui-overflow-show" +
932 this._getOverflowIndicator( this._opacity_top ) + " 0.3s 1 ease" );
933 this._overflow_bottom.css( "-webkit-animation", "ui-overflow-show" +
934 this._getOverflowIndicator( this._opacity_bottom ) + " 0.3s 1 ease" );
936 this._overflow_showed = true;
939 _hideOverflowIndicator: function () {
943 if ( !this.options.overflowEnable || !this._overflowAvail || this._softkeyboard ) {
947 if ( this._overflow_showed === false ) {
951 opacity_top = this._overflow_top.css( "opacity" );
952 opacity_bottom = this._overflow_bottom.css( "opacity" );
954 this._overflow_top.css( "opacity", "0" );
955 this._overflow_bottom.css( "opacity", "0" );
957 this._overflow_top.css( "-webkit-animation", "ui-overflow-hide" +
958 this._getOverflowIndicator( opacity_top ) + " 0.5s 1 ease" );
959 this._overflow_bottom.css( "-webkit-animation", "ui-overflow-hide" +
960 this._getOverflowIndicator( opacity_bottom ) + " 0.5s 1 ease" );
962 this._overflow_showed = false;
963 this._setOverflowIndicator();
966 _add_event: function () {
971 if ( this.options.eventType === "mouse" ) {
972 this._dragEvt = "mousedown mousemove mouseup click mousewheel";
974 this._dragCB = function ( e ) {
977 return self._handleDragStart( e,
978 e.clientX, e.clientY );
981 return self._handleDragMove( e,
982 e.clientX, e.clientY );
985 return self._handleDragStop( e );
988 return !self._didDrag;
991 var old = self.getScrollPosition();
992 self.scrollTo( -old.x,
993 -(old.y - e.originalEvent.wheelDelta) );
998 this._dragEvt = "touchstart touchmove touchend click";
1000 this._dragCB = function ( e ) {
1005 t = e.originalEvent.targetTouches[0];
1006 return self._handleDragStart( e,
1010 t = e.originalEvent.targetTouches[0];
1011 return self._handleDragMove( e,
1015 return self._handleDragStop( e );
1018 return !self._didDrag;
1023 $v.bind( this._dragEvt, this._dragCB );
1025 $v.bind( "keydown", function ( e ) {
1030 if ( e.keyCode == 9 ) {
1034 elem = $c.find(".ui-focus");
1036 if ( elem === undefined ) {
1040 elem_top = elem.offset().top;
1041 screen_h = $c.offset().top + $c.height() - elem.height();
1043 if ( self._softkeyboard ) {
1044 screen_h -= self._softkeyboardHeight;
1047 if ( ( elem_top < 0 ) || ( elem_top > screen_h ) ) {
1048 self.scrollTo( 0, self._sy - elem_top +
1049 elem.height() + $c.offset().top, 0);
1055 $v.bind( "keyup", function ( e ) {
1061 if ( e.keyCode != 9 ) {
1067 input = $( this ).find(":input");
1069 for ( i = 0; i < input.length; i++ ) {
1070 if ( !$( input[i] ).hasClass("ui-focus") ) {
1074 if ( i + 1 == input.length ) {
1075 elem = $( input[0] );
1077 elem = $( input[i + 1] );
1080 elem_top = elem.offset().top;
1081 screen_h = $c.offset().top + $c.height() - elem.height();
1083 if ( self._softkeyboard ) {
1084 screen_h -= self._softkeyboardHeight;
1087 if ( ( elem_top < 0 ) || ( elem_top > screen_h ) ) {
1088 self.scrollTo( 0, self._sy - elem_top +
1089 elem.height() + $c.offset().top, 0);
1100 $c.bind( "updatelayout", function ( e ) {
1103 view_h = self._getViewHeight();
1105 if ( !$c.height() || !view_h ) {
1106 self.scrollTo( 0, 0, 0 );
1110 sy = $c.height() - view_h;
1111 vh = view_h - self._view_height;
1113 self._view_height = view_h;
1115 if ( vh == 0 || vh > $c.height() / 2 ) {
1120 self.scrollTo( 0, 0, 0 );
1121 } else if ( self._sy - sy <= -vh ) {
1122 self.scrollTo( 0, self._sy,
1123 self.options.snapbackDuration );
1124 } else if ( self._sy - sy <= vh + self.options.moveThreshold ) {
1125 self.scrollTo( 0, sy,
1126 self.options.snapbackDuration );
1130 $( window ).bind( "resize", function ( e ) {
1132 view_h = self._getViewHeight();
1134 if ( $(".ui-page-active").get(0) !== $c.closest(".ui-page").get(0) ) {
1138 if ( !$c.height() || !view_h ) {
1142 focused = $c.find(".ui-focus");
1145 focused.trigger("resize.scrollview");
1148 /* calibration - after triggered throttledresize */
1149 setTimeout( function () {
1150 if ( self._sy < $c.height() - self._getViewHeight() ) {
1151 self.scrollTo( 0, $c.height() - self._getViewHeight(),
1152 self.options.overshootDuration );
1156 self._view_height = view_h;
1159 $( window ).bind( "vmouseout", function ( e ) {
1160 var drag_stop = false;
1162 if ( $(".ui-page-active").get(0) !== $c.closest(".ui-page").get(0) ) {
1166 if ( !self._dragging ) {
1170 if ( e.pageX < 0 || e.pageX > $( window ).width() ) {
1174 if ( e.pageY < 0 || e.pageY > $( window ).height() ) {
1179 self._hideScrollBars();
1180 self._hideOverflowIndicator();
1181 self._disableTracking();
1185 this._softkeyboard = false;
1186 this._softkeyboardHeight = 0;
1188 window.addEventListener( "softkeyboardchange", function ( e ) {
1189 if ( $(".ui-page-active").get(0) !== $c.closest(".ui-page").get(0) ) {
1193 self._softkeyboard = ( e.state === "on" ? true : false );
1194 self._softkeyboardHeight = e.height;
1197 $c.closest(".ui-page")
1198 .one( "pageshow", function ( e ) {
1199 self._view_offset = self._$view.offset().top - self._$clip.offset().top;
1200 self._view_height = self._getViewHeight();
1202 .bind( "pageshow", function ( e ) {
1203 /* should be called after pagelayout */
1204 setTimeout( function () {
1205 self._set_scrollbar_size();
1206 self._setScrollPosition( self._sx, self._sy );
1207 self._showScrollBars( 2000 );
1208 self._resetOverflowIndicator();
1213 _add_scrollbar: function () {
1214 var $c = this._$clip,
1215 prefix = "<div class=\"ui-scrollbar ui-scrollbar-",
1216 suffix = "\"><div class=\"ui-scrollbar-track\"><div class=\"ui-scrollbar-thumb\"></div></div></div>";
1218 if ( !this.options.showScrollBars ) {
1222 if ( this._vTracker ) {
1223 $c.append( prefix + "y" + suffix );
1224 this._$vScrollBar = $c.children(".ui-scrollbar-y");
1226 if ( this._hTracker ) {
1227 $c.append( prefix + "x" + suffix );
1228 this._$hScrollBar = $c.children(".ui-scrollbar-x");
1231 this._scrollbar_showed = false;
1234 _add_scroll_jump: function () {
1235 var $c = this._$clip,
1240 if ( !this.options.scrollJump ) {
1244 if ( this._vTracker ) {
1245 top_btn = $( '<div class="ui-scroll-jump-top-bg">' +
1246 '<div data-role="button" data-inline="true" data-icon="scrolltop" data-style="box"></div></div>' );
1247 $c.append( top_btn ).trigger("create");
1249 top_btn.bind( "vclick", function () {
1250 self.scrollTo( 0, 0, self.options.overshootDuration );
1254 if ( this._hTracker ) {
1255 left_btn = $( '<div class="ui-scroll-jump-left-bg">' +
1256 '<div data-role="button" data-inline="true" data-icon="scrollleft" data-style="box"></div></div>' );
1257 $c.append( left_btn ).trigger("create");
1259 left_btn.bind( "vclick", function () {
1260 self.scrollTo( 0, 0, self.options.overshootDuration );
1265 _add_overflow_indicator: function () {
1266 if ( !this.options.overflowEnable ) {
1270 this._overflow_top = $( '<div class="ui-overflow-indicator-top"></div>' );
1271 this._overflow_bottom = $( '<div class="ui-overflow-indicator-bottom"></div>' );
1273 this._$clip.append( this._overflow_top );
1274 this._$clip.append( this._overflow_bottom );
1276 this._opacity_top = "0.5";
1277 this._opacity_bottom = "0.5";
1278 this._overflow_showed = false;
1281 _set_scrollbar_size: function () {
1282 var $c = this._$clip,
1290 if ( !this.options.showScrollBars ) {
1294 if ( this._hTracker ) {
1297 this._maxX = cw - vw;
1299 if ( this._maxX > 0 ) {
1302 if ( this._$hScrollBar && vw ) {
1303 thumb = this._$hScrollBar.find(".ui-scrollbar-thumb");
1304 thumb.css( "width", (cw >= vw ? "0" :
1305 (Math.floor(cw / vw * 100) || 1) + "%") );
1309 if ( this._vTracker ) {
1311 vh = this._getViewHeight();
1312 this._maxY = ch - vh;
1314 if ( this._maxY > 0 ) {
1317 if ( this._$vScrollBar && vh ) {
1318 thumb = this._$vScrollBar.find(".ui-scrollbar-thumb");
1319 thumb.css( "height", (ch >= vh ? "0" :
1320 (Math.floor(ch / vh * 100) || 1) + "%") );
1322 this._overflowAvail = !!thumb.height();
1328 $.extend( MomentumTracker.prototype, {
1329 start: function ( pos, speed, duration, minPos, maxPos ) {
1330 var tstate = ( pos < minPos || pos > maxPos ) ?
1331 tstates.snapback : tstates.scrolling,
1334 this.state = ( speed !== 0 ) ? tstate : tstates.done;
1337 this.duration = ( this.state === tstates.snapback ) ?
1338 this.options.snapbackDuration : duration;
1339 this.minPos = minPos;
1340 this.maxPos = maxPos;
1342 this.fromPos = ( this.state === tstates.snapback ) ? this.pos : 0;
1343 pos_temp = ( this.pos < this.minPos ) ? this.minPos : this.maxPos;
1344 this.toPos = ( this.state === tstates.snapback ) ? pos_temp : 0;
1346 this.startTime = getCurrentTime();
1349 reset: function () {
1350 this.state = tstates.done;
1359 update: function ( overshootEnable ) {
1360 var state = this.state,
1361 cur_time = getCurrentTime(),
1362 duration = this.duration,
1363 elapsed = cur_time - this.startTime,
1368 if ( state === tstates.done ) {
1372 elapsed = elapsed > duration ? duration : elapsed;
1374 this.remained = duration - elapsed;
1376 if ( state === tstates.scrolling || state === tstates.overshot ) {
1378 ( 1 - $.easing[this.easing]( elapsed / duration,
1379 elapsed, 0, 1, duration ) );
1383 didOverShoot = ( state === tstates.scrolling ) &&
1384 ( x < this.minPos || x > this.maxPos );
1386 if ( didOverShoot ) {
1387 x = ( x < this.minPos ) ? this.minPos : this.maxPos;
1392 if ( state === tstates.overshot ) {
1393 if ( !overshootEnable ) {
1394 this.state = tstates.done;
1396 if ( elapsed >= duration ) {
1397 this.state = tstates.snapback;
1398 this.fromPos = this.pos;
1399 this.toPos = ( x < this.minPos ) ?
1400 this.minPos : this.maxPos;
1401 this.duration = this.options.snapbackDuration;
1402 this.startTime = cur_time;
1405 } else if ( state === tstates.scrolling ) {
1406 if ( didOverShoot && overshootEnable ) {
1407 this.state = tstates.overshot;
1408 this.speed = dx / 2;
1409 this.duration = this.options.overshootDuration;
1410 this.startTime = cur_time;
1411 } else if ( elapsed >= duration ) {
1412 this.state = tstates.done;
1415 } else if ( state === tstates.snapback ) {
1416 if ( elapsed >= duration ) {
1417 this.pos = this.toPos;
1418 this.state = tstates.done;
1420 this.pos = this.fromPos + (( this.toPos - this.fromPos ) *
1421 $.easing[this.easing]( elapsed / duration,
1422 elapsed, 0, 1, duration ));
1430 return this.state === tstates.done;
1433 isMin: function () {
1434 return this.pos === this.minPos;
1437 isMax: function () {
1438 return this.pos === this.maxPos;
1441 isAvail: function () {
1442 return !( this.minPos === this.maxPos );
1445 getRemained: function () {
1446 return this.remained;
1449 getPosition: function () {
1454 $( document ).bind( 'pagecreate create', function ( e ) {
1455 var $page = $( e.target ),
1456 content_scroll = $page.find(".ui-content").jqmData("scroll");
1458 /* content scroll */
1459 if ( $.support.scrollview === undefined ) {
1460 $.support.scrollview = true;
1463 if ( $.support.scrollview === true && content_scroll === undefined ) {
1464 content_scroll = "y";
1467 if ( content_scroll !== "y" ) {
1468 content_scroll = "none";
1471 $page.find(".ui-content").attr( "data-scroll", content_scroll );
1473 $page.find(":jqmData(scroll):not(.ui-scrollview-clip)").each( function () {
1474 if ( $( this ).hasClass("ui-scrolllistview") ) {
1475 $( this ).scrolllistview();
1477 var st = $( this ).jqmData("scroll"),
1478 dir = st && ( st.search(/^[xy]/) !== -1 ) ? st : null,
1479 content = $(this).hasClass("ui-content"),
1482 if ( st === "none" ) {
1487 direction: dir || undefined,
1488 overflowEnable: content,
1489 scrollMethod: $( this ).jqmData("scroll-method") || undefined,
1490 scrollJump: $( this ).jqmData("scroll-jump") || undefined
1493 $( this ).scrollview( opts );
1498 $( document ).bind( 'pageshow', function ( e ) {
1499 var $page = $( e.target ),
1500 scroll = $page.find(".ui-content").jqmData("scroll");
1502 if ( scroll === "y" ) {
1503 resizePageContentHeight( e.target );
1507 }( jQuery, window, document ) );