1 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
2 //>>description: Implements scroll by javascript
6 define( [ ], function ( ) {
7 //>>excludeEnd("jqmBuildExclude");
10 * jQuery Mobile Framework : scrollview plugin
11 * Copyright (c) 2010 Adobe Systems Incorporated - Kin Blas (jblas@adobe.com)
12 * Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
13 * Note: Code is in draft form and is subject to change
14 * Modified by Koeun Choi <koeun.choi@samsung.com>
15 * Modified by Minkyu Kang <mk7.kang@samsung.com>
18 (function ( $, window, document, undefined ) {
20 function resizePageContentHeight( page ) {
21 var $page = $( page ),
22 $content = $page.children(".ui-content"),
23 hh = $page.children(".ui-header").outerHeight() || 0,
24 fh = $page.children(".ui-footer").outerHeight() || 0,
25 pt = parseFloat( $content.css("padding-top") ),
26 pb = parseFloat( $content.css("padding-bottom") ),
27 wh = $( window ).height();
29 $content.height( wh - (hh + fh) - (pt + pb) );
32 function MomentumTracker( options ) {
33 this.options = $.extend( {}, options );
34 this.easing = "easeOutQuad";
45 function getCurrentTime() {
49 jQuery.widget( "tizen.scrollview", jQuery.mobile.widget, {
51 direction: null, // "x", "y", or null for both.
54 scrollDuration: 1000, // Duration of the scrolling animation in msecs.
55 overshootDuration: 250, // Duration of the overshoot animation in msecs.
56 snapbackDuration: 500, // Duration of the snapback animation in msecs.
58 moveThreshold: 30, // User must move this many pixels in any direction to trigger a scroll.
59 moveIntervalThreshold: 150, // Time between mousemoves must not exceed this threshold.
61 scrollMethod: "translate", // "translate", "position"
62 startEventName: "scrollstart",
63 updateEventName: "scrollupdate",
64 stopEventName: "scrollstop",
66 eventType: $.support.touch ? "touch" : "mouse",
69 overshootEnable: false,
70 outerScrollEnable: true,
75 _getViewHeight: function () {
76 return this._$view.height();
79 _getViewWidth: function () {
80 return this._$view.width();
83 _makePositioned: function ( $ele ) {
84 if ( $ele.css("position") === "static" ) {
85 $ele.css( "position", "relative" );
89 _create: function () {
93 this._$clip = $( this.element ).addClass("ui-scrollview-clip");
95 if ( this._$clip.children(".ui-scrollview-view").length ) {
96 this._$view = this._$clip.children(".ui-scrollview-view");
98 this._$view = this._$clip.wrapInner("<div></div>").children()
99 .addClass("ui-scrollview-view");
102 if ( this.options.scrollMethod === "translate" ) {
103 if ( this._$view.css("transform") === undefined ) {
104 this.options.scrollMethod = "position";
108 this._$clip.css( "overflow", "hidden" );
109 this._makePositioned( this._$clip );
111 this._makePositioned( this._$view );
112 this._$view.css( { left: 0, top: 0 } );
114 this._view_height = this._getViewHeight();
119 direction = this.options.direction;
121 this._hTracker = ( direction !== "y" ) ?
122 new MomentumTracker( this.options ) : null;
123 this._vTracker = ( direction !== "x" ) ?
124 new MomentumTracker( this.options ) : null;
126 this._timerInterval = this.options.timerInterval;
129 this._timerCB = function () {
130 self._handleMomentumScroll();
134 this._add_scrollbar();
135 this._add_scroll_jump();
136 this._add_overflow_indicator();
139 _startMScroll: function ( speedX, speedY ) {
140 var keepGoing = false,
141 duration = this.options.scrollDuration,
147 this._$clip.trigger( this.options.startEventName );
150 c = this._$clip.width();
151 v = this._getViewWidth();
153 if ( (( this._sx === 0 && speedX > 0 ) ||
154 ( this._sx === -(v - c) && speedX < 0 )) &&
159 ht.start( this._sx, speedX,
160 duration, (v > c) ? -(v - c) : 0, 0 );
161 keepGoing = !ht.done();
165 c = this._$clip.height();
166 v = this._getViewHeight();
168 if ( (( this._sy === 0 && speedY > 0 ) ||
169 ( this._sy === -(v - c) && speedY < 0 )) &&
174 vt.start( this._sy, speedY,
175 duration, (v > c) ? -(v - c) : 0, 0 );
176 keepGoing = keepGoing || !vt.done();
180 this._timerID = setTimeout( this._timerCB, this._timerInterval );
186 _stopMScroll: function () {
187 if ( this._timerID ) {
188 this._$clip.trigger( this.options.stopEventName );
189 clearTimeout( this._timerID );
193 if ( this._vTracker ) {
194 this._vTracker.reset();
197 if ( this._hTracker ) {
198 this._hTracker.reset();
201 this._hideScrollBars();
202 this._hideOverflowIndicator();
205 _handleMomentumScroll: function () {
206 var keepGoing = false,
211 end_effect = function ( dir ) {
212 setTimeout( function () {
213 self._effect_dir = dir;
214 self._setEndEffect( "in" );
217 setTimeout( function () {
218 self._setEndEffect( "out" );
224 if ( this._outerScrolling ) {
229 vt.update( this.options.overshootEnable );
230 y = vt.getPosition();
231 keepGoing = !vt.done();
233 if ( vt.getRemained() > this.options.overshootDuration ) {
234 scroll_height = this._getViewHeight() - this._$clip.height();
236 if ( !vt.isAvail() ) {
237 if ( this._speedY > 0 ) {
238 this._outerScroll( vt.getRemained() / 3, scroll_height );
240 this._outerScroll( y - vt.getRemained() / 3, scroll_height );
242 } else if ( vt.isMin() ) {
243 this._outerScroll( y - vt.getRemained() / 3, scroll_height );
245 if ( scroll_height > 0 ) {
248 } else if ( vt.isMax() ) {
249 this._outerScroll( vt.getRemained() / 3, scroll_height );
251 if ( scroll_height > 0 ) {
259 ht.update( this.options.overshootEnable );
260 x = ht.getPosition();
261 keepGoing = keepGoing || !ht.done();
264 this._setScrollPosition( x, y );
265 this._$clip.trigger( this.options.updateEventName,
266 [ { x: x, y: y } ] );
269 this._timerID = setTimeout( this._timerCB, this._timerInterval );
275 _setElementTransform: function ( $ele, x, y, duration ) {
279 if ( !duration || duration === undefined ) {
282 transition = "-webkit-transform " + duration / 1000 + "s ease-out";
285 if ( $.support.cssTransform3d ) {
286 translate = "translate3d(" + x + "," + y + ", 0px)";
288 translate = "translate(" + x + "," + y + ")";
292 "-moz-transform": translate,
293 "-webkit-transform": translate,
294 "-ms-transform": translate,
295 "-o-transform": translate,
296 "transform": translate,
297 "-webkit-transition": transition
301 _setEndEffect: function ( dir ) {
302 var scroll_height = this._getViewHeight() - this._$clip.height();
304 if ( this._softkeyboard ) {
305 if ( this._effect_dir ) {
306 this._outerScroll( -scroll_height - this._softkeyboardHeight,
309 this._outerScroll( this._softkeyboardHeight, scroll_height );
314 if ( dir === "in" ) {
315 if ( this._endEffect ) {
319 this._endEffect = true;
320 this._setOverflowIndicator( this._effect_dir );
321 this._showOverflowIndicator();
322 } else if ( dir === "out" ) {
323 if ( !this._endEffect ) {
327 this._endEffect = false;
329 this._endEffect = false;
330 this._setOverflowIndicator();
331 this._showOverflowIndicator();
335 _setCalibration: function ( x, y ) {
336 if ( this.options.overshootEnable ) {
342 var $v = this._$view,
344 dirLock = this._directionLock,
348 if ( dirLock !== "y" && this._hTracker ) {
349 scroll_width = $v.width() - $c.width();
353 } else if ( x < -scroll_width ) {
354 this._sx = -scroll_width;
359 if ( scroll_width < 0 ) {
364 if ( dirLock !== "x" && this._vTracker ) {
365 scroll_height = this._getViewHeight() - $c.height();
370 if ( this._didDrag && scroll_height > 0 ) {
371 this._effect_dir = 0;
372 this._setEndEffect( "in" );
374 } else if ( y < -scroll_height ) {
375 this._sy = -scroll_height;
377 if ( this._didDrag && scroll_height > 0 ) {
378 this._effect_dir = 1;
379 this._setEndEffect( "in" );
382 if ( this._endEffect && this._sy !== y ) {
383 this._setEndEffect();
389 if ( scroll_height < 0 ) {
395 _setScrollPosition: function ( x, y, duration ) {
396 var $v = this._$view,
397 sm = this.options.scrollMethod,
398 $vsb = this._$vScrollBar,
399 $hsb = this._$hScrollBar,
402 this._setCalibration( x, y );
407 if ( sm === "translate" ) {
408 this._setElementTransform( $v, x + "px", y + "px", duration );
410 $v.css( {left: x + "px", top: y + "px"} );
414 $sbt = $vsb.find(".ui-scrollbar-thumb");
416 if ( sm === "translate" ) {
417 this._setElementTransform( $sbt, "0px",
418 -y / this._getViewHeight() * $sbt.parent().height() + "px",
421 $sbt.css( "top", -y / this._getViewHeight() * 100 + "%" );
426 $sbt = $hsb.find(".ui-scrollbar-thumb");
428 if ( sm === "translate" ) {
429 this._setElementTransform( $sbt,
430 -x / $v.width() * $sbt.parent().width() + "px", "0px",
433 $sbt.css("left", -x / $v.width() * 100 + "%");
438 _outerScroll: function ( y, scroll_height ) {
440 top = $( window ).scrollTop() - window.screenTop,
442 duration = this.options.snapbackDuration,
443 start = getCurrentTime(),
446 if ( !this.options.outerScrollEnable ) {
450 if ( this._$clip.jqmData("scroll") !== "y" ) {
454 if ( this._outerScrolling ) {
459 sy = ( window.screenTop ? window.screenTop : -y );
460 } else if ( y < -scroll_height ) {
461 sy = -y - scroll_height;
466 tfunc = function () {
467 var elapsed = getCurrentTime() - start;
469 if ( elapsed >= duration ) {
470 window.scrollTo( 0, top + sy );
471 self._outerScrolling = undefined;
475 ec = $.easing.easeOutQuad( elapsed / duration,
476 elapsed, 0, 1, duration );
478 window.scrollTo( 0, top + ( sy * ec ) );
479 self._outerScrolling = setTimeout( tfunc, self._timerInterval );
482 this._outerScrolling = setTimeout( tfunc, self._timerInterval );
485 _scrollTo: function ( x, y, duration ) {
487 start = getCurrentTime(),
488 efunc = $.easing.easeOutQuad,
498 tfunc = function () {
499 var elapsed = getCurrentTime() - start,
502 if ( elapsed >= duration ) {
504 self._setScrollPosition( x, y );
506 ec = efunc( elapsed / duration, elapsed, 0, 1, duration );
508 self._setScrollPosition( sx + ( dx * ec ), sy + ( dy * ec ) );
509 self._timerID = setTimeout( tfunc, self._timerInterval );
513 this._timerID = setTimeout( tfunc, this._timerInterval );
516 scrollTo: function ( x, y, duration ) {
518 this._didDrag = false;
520 if ( !duration || this.options.scrollMethod === "translate" ) {
521 this._setScrollPosition( x, y, duration );
523 this._scrollTo( x, y, duration );
527 getScrollPosition: function () {
528 return { x: -this._sx, y: -this._sy };
531 skipDragging: function ( value ) {
532 this._skip_dragging = value;
535 _getScrollHierarchy: function () {
539 this._$clip.parents( ".ui-scrollview-clip").each( function () {
540 d = $( this ).jqmData("scrollview");
548 _getAncestorByDirection: function ( dir ) {
549 var svh = this._getScrollHierarchy(),
556 svdir = sv.options.direction;
558 if (!svdir || svdir === dir) {
565 _handleDragStart: function ( e, ex, ey ) {
568 this._didDrag = false;
569 this._skip_dragging = false;
571 var target = $( e.target ),
574 svdir = this.options.direction;
576 /* should prevent the default behavior when click the button */
577 this._is_button = target.is( '.ui-btn' ) ||
578 target.is( '.ui-btn-text' ) ||
579 target.is( '.ui-btn-inner' ) ||
580 target.is( '.ui-btn-inner .ui-icon' );
582 /* should prevent the default behavior when click the slider */
583 if ( target.parents('.ui-slider').length || target.is('.ui-slider') ) {
584 this._skip_dragging = true;
588 if ( target.is('textarea') ) {
589 target.bind( "scroll", function () {
590 self._skip_dragging = true;
591 target.unbind("scroll");
596 * We need to prevent the default behavior to
597 * suppress accidental selection of text, etc.
599 this._is_inputbox = target.is(':input') ||
600 target.parents(':input').length > 0;
602 if ( this._is_inputbox ) {
603 target.one( "resize.scrollview", function () {
604 if ( ey > $c.height() ) {
605 self.scrollTo( -ex, self._sy - ey + $c.height(),
606 self.options.snapbackDuration );
611 if ( this.options.eventType === "mouse" && !this._is_inputbox && !this._is_button ) {
618 this._doSnapBackX = false;
619 this._doSnapBackY = false;
622 this._directionLock = "";
625 this._enableTracking();
627 this._set_scrollbar_size();
630 _propagateDragMove: function ( sv, e, ex, ey, dir ) {
631 this._hideScrollBars();
632 this._hideOverflowIndicator();
633 this._disableTracking();
634 sv._handleDragStart( e, ex, ey );
635 sv._directionLock = dir;
636 sv._didDrag = this._didDrag;
639 _handleDragMove: function ( e, ex, ey ) {
640 if ( this._skip_dragging ) {
644 if ( !this._dragging ) {
648 if ( !this._is_inputbox && !this._is_button ) {
652 var mt = this.options.moveThreshold,
653 dx = ex - this._lastX,
654 dy = ey - this._lastY,
655 svdir = this.options.direction,
665 this._lastMove = getCurrentTime();
667 if ( !this._directionLock ) {
671 if ( x < mt && y < mt ) {
675 if ( x < y && (x / y) < 0.5 ) {
677 } else if ( x > y && (y / x) < 0.5 ) {
681 if ( svdir && dir && svdir !== dir ) {
683 * This scrollview can't handle the direction the user
684 * is attempting to scroll. Find an ancestor scrollview
685 * that can handle the request.
688 sv = this._getAncestorByDirection( dir );
690 this._propagateDragMove( sv, e, ex, ey, dir );
695 this._directionLock = svdir || (dir || "none");
700 dirLock = this._directionLock;
702 if ( dirLock !== "y" && this._hTracker ) {
707 this._doSnapBackX = false;
709 scope = ( newX > 0 || newX < this._maxX );
711 if ( scope && dirLock === "x" ) {
712 sv = this._getAncestorByDirection("x");
714 this._setScrollPosition( newX > 0 ?
715 0 : this._maxX, newY );
716 this._propagateDragMove( sv, e, ex, ey, dir );
720 newX = x + ( dx / 2 );
721 this._doSnapBackX = true;
725 if ( dirLock !== "x" && this._vTracker ) {
726 if ( Math.abs( this._startY - ey ) < mt && dirLock !== "xy" ) {
734 this._doSnapBackY = false;
736 scope = ( newY > 0 || newY < this._maxY );
738 if ( scope && dirLock === "y" ) {
739 sv = this._getAncestorByDirection("y");
741 this._setScrollPosition( newX,
742 newY > 0 ? 0 : this._maxY );
743 this._propagateDragMove( sv, e, ex, ey, dir );
747 newY = y + ( dy / 2 );
748 this._doSnapBackY = true;
752 if ( this.options.overshootEnable === false ) {
753 this._doSnapBackX = false;
754 this._doSnapBackY = false;
760 this._setScrollPosition( newX, newY );
762 if ( this._didDrag === false ) {
763 this._didDrag = true;
764 this._showScrollBars();
765 this._showOverflowIndicator();
767 this._$clip.parents(".ui-scrollview-clip").each( function () {
768 $( this ).scrollview( "skipDragging", true );
773 _handleDragStop: function ( e ) {
776 if ( this._skip_dragging ) {
780 var l = this._lastMove,
781 t = getCurrentTime(),
782 doScroll = (l && (t - l) <= this.options.moveIntervalThreshold),
783 sx = ( this._hTracker && this._speedX && doScroll ) ?
784 this._speedX : ( this._doSnapBackX ? 1 : 0 ),
785 sy = ( this._vTracker && this._speedY && doScroll ) ?
786 this._speedY : ( this._doSnapBackY ? 1 : 0 ),
787 svdir = this.options.direction,
792 if ( !this._setGestureScroll( sx, sy ) ) {
793 this._startMScroll( sx, sy );
796 this._hideScrollBars();
797 this._hideOverflowIndicator();
800 this._disableTracking();
802 if ( this._endEffect ) {
803 setTimeout( function () {
804 self._setEndEffect( "out" );
805 self._hideScrollBars();
806 self._hideOverflowIndicator();
810 return !this._didDrag;
813 _setGestureScroll: function ( sx, sy ) {
815 reset = function () {
816 clearTimeout( self._gesture_timer );
817 self._gesture_dir = 0;
818 self._gesture_count = 0;
819 self._gesture_timer = undefined;
832 if ( Math.abs( sx ) > Math.abs( sy ) ) {
833 dir = sx > 0 ? direction.left : direction.right;
835 dir = sy > 0 ? direction.top : direction.bottom;
838 if ( !this._gesture_timer ) {
839 this._gesture_count = 1;
840 this._gesture_dir = dir;
842 this._gesture_timer = setTimeout( function () {
849 if ( this._gesture_dir !== dir ) {
854 this._gesture_count++;
856 if ( this._gesture_count === 3 ) {
859 this.scrollTo( this._sx, 0, this.options.overshootDuration );
861 case direction.bottom:
862 this.scrollTo( this._sx, -( this._getViewHeight() - this._$clip.height() ),
863 this.options.overshootDuration );
866 this.scrollTo( 0, this._sy, this.options.overshootDuration );
868 case direction.right:
869 this.scrollTo( -( this._getViewWidth() - this._$clip.width() ), this._sy,
870 this.options.overshootDuration );
875 this._didDrag = true;
883 _enableTracking: function () {
884 this._dragging = true;
887 _disableTracking: function () {
888 this._dragging = false;
891 _showScrollBars: function ( interval ) {
892 var vclass = "ui-scrollbar-visible",
895 if ( !this.options.showScrollBars ) {
898 if ( this._scrollbar_showed ) {
902 if ( this._$vScrollBar ) {
903 this._$vScrollBar.addClass( vclass );
905 if ( this._$hScrollBar ) {
906 this._$hScrollBar.addClass( vclass );
909 this._scrollbar_showed = true;
912 setTimeout( function () {
913 self._hideScrollBars();
918 _hideScrollBars: function () {
919 var vclass = "ui-scrollbar-visible";
921 if ( !this.options.showScrollBars ) {
924 if ( !this._scrollbar_showed ) {
928 if ( this._$vScrollBar ) {
929 this._$vScrollBar.removeClass( vclass );
931 if ( this._$hScrollBar ) {
932 this._$hScrollBar.removeClass( vclass );
935 this._scrollbar_showed = false;
938 _setOverflowIndicator: function ( dir ) {
940 this._opacity_top = "0";
941 this._opacity_bottom = "0.8";
942 } else if ( dir === 0 ) {
943 this._opacity_top = "0.8";
944 this._opacity_bottom = "0";
946 this._opacity_top = "0.5";
947 this._opacity_bottom = "0.5";
951 _showOverflowIndicator: function () {
952 if ( !this.options.overflowEnable || !this._overflowAvail || this._softkeyboard ) {
956 this._overflow_top.animate( { opacity: this._opacity_top }, 300 );
957 this._overflow_bottom.animate( { opacity: this._opacity_bottom }, 300 );
959 this._overflow_showed = true;
962 _hideOverflowIndicator: function () {
963 if ( !this.options.overflowEnable || !this._overflowAvail || this._softkeyboard ) {
967 if ( this._overflow_showed === false ) {
971 this._overflow_top.animate( { opacity: 0 }, 300 );
972 this._overflow_bottom.animate( { opacity: 0 }, 300 );
974 this._overflow_showed = false;
975 this._setOverflowIndicator();
978 _add_event: function () {
983 if ( this.options.eventType === "mouse" ) {
984 this._dragEvt = "mousedown mousemove mouseup click mousewheel";
986 this._dragCB = function ( e ) {
989 return self._handleDragStart( e,
990 e.clientX, e.clientY );
993 return self._handleDragMove( e,
994 e.clientX, e.clientY );
997 return self._handleDragStop( e );
1000 return !self._didDrag;
1003 var old = self.getScrollPosition();
1004 self.scrollTo( -old.x,
1005 -(old.y - e.originalEvent.wheelDelta) );
1010 this._dragEvt = "touchstart touchmove touchend click";
1012 this._dragCB = function ( e ) {
1013 var touches = e.originalEvent.touches;
1017 if ( touches.length != 1) {
1021 return self._handleDragStart( e,
1022 touches[0].pageX, touches[0].pageY );
1025 if ( touches.length != 1) {
1029 return self._handleDragMove( e,
1030 touches[0].pageX, touches[0].pageY );
1033 if ( touches.length != 0) {
1037 return self._handleDragStop( e );
1040 return !self._didDrag;
1045 $v.bind( this._dragEvt, this._dragCB );
1047 $v.bind( "keydown", function ( e ) {
1050 scroll_top = $( window ).scrollTop() - window.screenTop,
1053 if ( e.keyCode == 9 ) {
1057 elem = $c.find(".ui-focus");
1059 if ( elem === undefined ) {
1063 elem_top = elem.offset().top - scroll_top;
1064 screen_h = $c.offset().top + $c.height() - elem.height();
1066 if ( self._softkeyboard ) {
1067 screen_h -= self._softkeyboardHeight;
1070 if ( ( elem_top < $c.offset().top ) || ( elem_top > screen_h ) ) {
1071 self.scrollTo( 0, self._sy -
1072 ( elem_top - $c.offset().top - elem.height() ) );
1078 $v.bind( "keyup", function ( e ) {
1082 scroll_top = $( window ).scrollTop() - window.screenTop,
1085 if ( e.keyCode != 9 ) {
1091 input = $( this ).find(":input");
1093 for ( i = 0; i < input.length; i++ ) {
1094 if ( !$( input[i] ).hasClass("ui-focus") ) {
1098 if ( i + 1 == input.length ) {
1099 elem = $( input[0] );
1101 elem = $( input[i + 1] );
1104 elem_top = elem.offset().top - scroll_top;
1105 screen_h = $c.offset().top + $c.height() - elem.height();
1107 if ( self._softkeyboard ) {
1108 screen_h -= self._softkeyboardHeight;
1111 if ( ( elem_top < 0 ) || ( elem_top > screen_h ) ) {
1112 self.scrollTo( 0, self._sy - elem_top +
1113 elem.height() + $c.offset().top, 0);
1124 $c.bind( "updatelayout", function ( e ) {
1127 view_h = self._getViewHeight();
1129 if ( !$c.height() || !view_h ) {
1130 self.scrollTo( 0, 0, 0 );
1134 sy = $c.height() - view_h;
1135 vh = view_h - self._view_height;
1137 self._view_height = view_h;
1139 if ( vh == 0 || vh > $c.height() / 2 ) {
1144 self.scrollTo( 0, 0, 0 );
1145 } else if ( self._sy - sy <= -vh ) {
1146 self.scrollTo( 0, self._sy,
1147 self.options.snapbackDuration );
1148 } else if ( self._sy - sy <= vh + self.options.moveThreshold ) {
1149 self.scrollTo( 0, sy,
1150 self.options.snapbackDuration );
1154 $( window ).bind( "resize", function ( e ) {
1156 view_h = self._getViewHeight();
1158 if ( $(".ui-page-active").get(0) !== $c.closest(".ui-page").get(0) ) {
1162 if ( !$c.height() || !view_h ) {
1166 focused = $c.find(".ui-focus");
1169 focused.trigger("resize.scrollview");
1172 /* calibration - after triggered throttledresize */
1173 setTimeout( function () {
1174 if ( self._sy < $c.height() - self._getViewHeight() ) {
1175 self.scrollTo( 0, $c.height() - self._getViewHeight(),
1176 self.options.overshootDuration );
1180 self._view_height = view_h;
1183 $( window ).bind( "vmouseout", function ( e ) {
1184 var drag_stop = false;
1186 if ( $(".ui-page-active").get(0) !== $c.closest(".ui-page").get(0) ) {
1190 if ( !self._dragging ) {
1194 if ( e.pageX < 0 || e.pageX > $( window ).width() ) {
1198 if ( e.pageY < 0 || e.pageY > $( window ).height() ) {
1203 self._hideScrollBars();
1204 self._hideOverflowIndicator();
1205 self._disableTracking();
1209 this._softkeyboard = false;
1210 this._softkeyboardHeight = 0;
1212 window.addEventListener( "softkeyboardchange", function ( e ) {
1213 if ( $(".ui-page-active").get(0) !== $c.closest(".ui-page").get(0) ) {
1217 self._softkeyboard = ( e.state === "on" ? true : false );
1218 self._softkeyboardHeight = parseInt( e.height ) *
1219 ( $( window ).width() / window.screen.availWidth );
1222 $c.closest(".ui-page")
1223 .bind( "pageshow", function ( e ) {
1224 /* should be called after pagelayout */
1225 setTimeout( function () {
1226 self._view_height = self._getViewHeight();
1227 self._set_scrollbar_size();
1228 self._setScrollPosition( self._sx, self._sy );
1229 self._showScrollBars( 2000 );
1234 _add_scrollbar: function () {
1235 var $c = this._$clip,
1236 prefix = "<div class=\"ui-scrollbar ui-scrollbar-",
1237 suffix = "\"><div class=\"ui-scrollbar-track\"><div class=\"ui-scrollbar-thumb\"></div></div></div>";
1239 if ( !this.options.showScrollBars ) {
1243 if ( this._vTracker ) {
1244 $c.append( prefix + "y" + suffix );
1245 this._$vScrollBar = $c.children(".ui-scrollbar-y");
1247 if ( this._hTracker ) {
1248 $c.append( prefix + "x" + suffix );
1249 this._$hScrollBar = $c.children(".ui-scrollbar-x");
1252 this._scrollbar_showed = false;
1255 _add_scroll_jump: function () {
1256 var $c = this._$clip,
1261 if ( !this.options.scrollJump ) {
1265 if ( this._vTracker ) {
1266 top_btn = $( '<div class="ui-scroll-jump-top-bg">' +
1267 '<div data-role="button" data-inline="true" data-icon="scrolltop" data-style="box"></div></div>' );
1268 $c.append( top_btn ).trigger("create");
1270 top_btn.bind( "vclick", function () {
1271 self.scrollTo( 0, 0, self.options.overshootDuration );
1275 if ( this._hTracker ) {
1276 left_btn = $( '<div class="ui-scroll-jump-left-bg">' +
1277 '<div data-role="button" data-inline="true" data-icon="scrollleft" data-style="box"></div></div>' );
1278 $c.append( left_btn ).trigger("create");
1280 left_btn.bind( "vclick", function () {
1281 self.scrollTo( 0, 0, self.options.overshootDuration );
1286 _add_overflow_indicator: function () {
1287 if ( !this.options.overflowEnable ) {
1291 this._overflow_top = $( '<div class="ui-overflow-indicator-top"></div>' );
1292 this._overflow_bottom = $( '<div class="ui-overflow-indicator-bottom"></div>' );
1294 this._$clip.append( this._overflow_top );
1295 this._$clip.append( this._overflow_bottom );
1297 this._opacity_top = "0.5";
1298 this._opacity_bottom = "0.5";
1299 this._overflow_showed = false;
1302 _set_scrollbar_size: function () {
1303 var $c = this._$clip,
1311 if ( !this.options.showScrollBars ) {
1315 if ( this._hTracker ) {
1318 this._maxX = cw - vw;
1320 if ( this._maxX > 0 ) {
1323 if ( this._$hScrollBar && vw ) {
1324 thumb = this._$hScrollBar.find(".ui-scrollbar-thumb");
1325 thumb.css( "width", (cw >= vw ? "0" :
1326 (Math.floor(cw / vw * 100) || 1) + "%") );
1330 if ( this._vTracker ) {
1332 vh = this._getViewHeight();
1333 this._maxY = ch - vh;
1335 if ( this._maxY > 0 ) {
1338 if ( this._$vScrollBar && vh ) {
1339 thumb = this._$vScrollBar.find(".ui-scrollbar-thumb");
1340 thumb.css( "height", (ch >= vh ? "0" :
1341 (Math.floor(ch / vh * 100) || 1) + "%") );
1343 this._overflowAvail = !!thumb.height();
1349 $.extend( MomentumTracker.prototype, {
1350 start: function ( pos, speed, duration, minPos, maxPos ) {
1351 var tstate = ( pos < minPos || pos > maxPos ) ?
1352 tstates.snapback : tstates.scrolling,
1355 this.state = ( speed !== 0 ) ? tstate : tstates.done;
1358 this.duration = ( this.state === tstates.snapback ) ?
1359 this.options.snapbackDuration : duration;
1360 this.minPos = minPos;
1361 this.maxPos = maxPos;
1363 this.fromPos = ( this.state === tstates.snapback ) ? this.pos : 0;
1364 pos_temp = ( this.pos < this.minPos ) ? this.minPos : this.maxPos;
1365 this.toPos = ( this.state === tstates.snapback ) ? pos_temp : 0;
1367 this.startTime = getCurrentTime();
1370 reset: function () {
1371 this.state = tstates.done;
1380 update: function ( overshootEnable ) {
1381 var state = this.state,
1382 cur_time = getCurrentTime(),
1383 duration = this.duration,
1384 elapsed = cur_time - this.startTime,
1389 if ( state === tstates.done ) {
1393 elapsed = elapsed > duration ? duration : elapsed;
1395 this.remained = duration - elapsed;
1397 if ( state === tstates.scrolling || state === tstates.overshot ) {
1399 ( 1 - $.easing[this.easing]( elapsed / duration,
1400 elapsed, 0, 1, duration ) );
1404 didOverShoot = ( state === tstates.scrolling ) &&
1405 ( x < this.minPos || x > this.maxPos );
1407 if ( didOverShoot ) {
1408 x = ( x < this.minPos ) ? this.minPos : this.maxPos;
1413 if ( state === tstates.overshot ) {
1414 if ( !overshootEnable ) {
1415 this.state = tstates.done;
1417 if ( elapsed >= duration ) {
1418 this.state = tstates.snapback;
1419 this.fromPos = this.pos;
1420 this.toPos = ( x < this.minPos ) ?
1421 this.minPos : this.maxPos;
1422 this.duration = this.options.snapbackDuration;
1423 this.startTime = cur_time;
1426 } else if ( state === tstates.scrolling ) {
1427 if ( didOverShoot && overshootEnable ) {
1428 this.state = tstates.overshot;
1429 this.speed = dx / 2;
1430 this.duration = this.options.overshootDuration;
1431 this.startTime = cur_time;
1432 } else if ( elapsed >= duration ) {
1433 this.state = tstates.done;
1436 } else if ( state === tstates.snapback ) {
1437 if ( elapsed >= duration ) {
1438 this.pos = this.toPos;
1439 this.state = tstates.done;
1441 this.pos = this.fromPos + (( this.toPos - this.fromPos ) *
1442 $.easing[this.easing]( elapsed / duration,
1443 elapsed, 0, 1, duration ));
1451 return this.state === tstates.done;
1454 isMin: function () {
1455 return this.pos === this.minPos;
1458 isMax: function () {
1459 return this.pos === this.maxPos;
1462 isAvail: function () {
1463 return !( this.minPos === this.maxPos );
1466 getRemained: function () {
1467 return this.remained;
1470 getPosition: function () {
1475 $( document ).bind( 'pagecreate create', function ( e ) {
1476 var $page = $( e.target ),
1477 content_scroll = $page.find(".ui-content").jqmData("scroll");
1479 /* content scroll */
1480 if ( $.support.scrollview === undefined ) {
1481 $.support.scrollview = true;
1484 if ( $.support.scrollview === true && content_scroll === undefined ) {
1485 content_scroll = "y";
1488 if ( content_scroll !== "y" ) {
1489 content_scroll = "none";
1492 $page.find(".ui-content").attr( "data-scroll", content_scroll );
1494 $page.find(":jqmData(scroll)").not(".ui-scrollview-clip").each( function () {
1495 if ( $( this ).hasClass("ui-scrolllistview") ) {
1496 $( this ).scrolllistview();
1498 var st = $( this ).jqmData("scroll"),
1499 dir = st && ( st.search(/^[xy]/) !== -1 ) ? st : null,
1500 content = $(this).hasClass("ui-content"),
1503 if ( st === "none" ) {
1508 direction: dir || undefined,
1509 overflowEnable: content,
1510 scrollMethod: $( this ).jqmData("scroll-method") || undefined,
1511 scrollJump: $( this ).jqmData("scroll-jump") || undefined
1514 $( this ).scrollview( opts );
1519 $( document ).bind( 'pageshow', function ( e ) {
1520 var $page = $( e.target ),
1521 scroll = $page.find(".ui-content").jqmData("scroll");
1523 if ( scroll === "y" ) {
1524 resizePageContentHeight( e.target );
1528 }( jQuery, window, document ) );
1530 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
1532 //>>excludeEnd("jqmBuildExclude");