scrollview: adds support x axis gesture scroll
[platform/framework/web/web-ui-fw.git] / src / js / jquery.mobile.tizen.scrollview.js
1 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
2 //>>description: Implements scroll by javascript
3 //>>label: Scrollview
4 //>>group: Tizen:Core
5
6 define( [ ], function ( ) {
7 //>>excludeEnd("jqmBuildExclude");
8
9 /*
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>
16 */
17
18 (function ( $, window, document, undefined ) {
19
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();
28
29                 $content.height( wh - (hh + fh) - (pt + pb) );
30         }
31
32         function MomentumTracker( options ) {
33                 this.options = $.extend( {}, options );
34                 this.easing = "easeOutQuad";
35                 this.reset();
36         }
37
38         var tstates = {
39                 scrolling: 0,
40                 overshot:  1,
41                 snapback:  2,
42                 done:      3
43         };
44
45         function getCurrentTime() {
46                 return Date.now();
47         }
48
49         jQuery.widget( "tizen.scrollview", jQuery.mobile.widget, {
50                 options: {
51                         direction:         null,  // "x", "y", or null for both.
52
53                         timerInterval:     10,
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.
57
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.
60
61                         scrollMethod:      "translate",  // "translate", "position"
62                         startEventName:    "scrollstart",
63                         updateEventName:   "scrollupdate",
64                         stopEventName:     "scrollstop",
65
66                         eventType:         $.support.touch ? "touch" : "mouse",
67
68                         showScrollBars:    true,
69                         overshootEnable:   false,
70                         outerScrollEnable: true,
71                         overflowEnable:    true,
72                         scrollJump:        false,
73                 },
74
75                 _getViewHeight: function () {
76                         return this._$view.height();
77                 },
78
79                 _makePositioned: function ( $ele ) {
80                         if ( $ele.css("position") === "static" ) {
81                                 $ele.css( "position", "relative" );
82                         }
83                 },
84
85                 _create: function () {
86                         var direction,
87                                 self = this;
88
89                         this._$clip = $( this.element ).addClass("ui-scrollview-clip");
90
91                         if ( this._$clip.children(".ui-scrollview-view").length ) {
92                                 this._$view = this._$clip.children(".ui-scrollview-view");
93                         } else {
94                                 this._$view = this._$clip.wrapInner("<div></div>").children()
95                                                         .addClass("ui-scrollview-view");
96                         }
97
98                         if ( this.options.scrollMethod === "translate" ) {
99                                 if ( this._$view.css("transform") === undefined ) {
100                                         this.options.scrollMethod = "position";
101                                 }
102                         }
103
104                         this._$clip.css( "overflow", "hidden" );
105                         this._makePositioned( this._$clip );
106
107                         this._makePositioned( this._$view );
108                         this._$view.css( { left: 0, top: 0 } );
109
110                         this._view_height = this._getViewHeight();
111
112                         this._sx = 0;
113                         this._sy = 0;
114
115                         direction = this.options.direction;
116
117                         this._hTracker = ( direction !== "y" ) ?
118                                         new MomentumTracker( this.options ) : null;
119                         this._vTracker = ( direction !== "x" ) ?
120                                         new MomentumTracker( this.options ) : null;
121
122                         this._timerInterval = this.options.timerInterval;
123                         this._timerID = 0;
124
125                         this._timerCB = function () {
126                                 self._handleMomentumScroll();
127                         };
128
129                         this._add_event();
130                         this._add_scrollbar();
131                         this._add_scroll_jump();
132                         this._add_overflow_indicator();
133                 },
134
135                 _startMScroll: function ( speedX, speedY ) {
136                         var keepGoing = false,
137                                 duration = this.options.scrollDuration,
138                                 ht = this._hTracker,
139                                 vt = this._vTracker,
140                                 c,
141                                 v;
142
143                         this._$clip.trigger( this.options.startEventName );
144
145                         if ( ht ) {
146                                 c = this._$clip.width();
147                                 v = this._$view.width();
148
149                                 if ( (( this._sx === 0 && speedX > 0 ) ||
150                                         ( this._sx === -(v - c) && speedX < 0 )) &&
151                                                 v > c ) {
152                                         return;
153                                 }
154
155                                 ht.start( this._sx, speedX,
156                                         duration, (v > c) ? -(v - c) : 0, 0 );
157                                 keepGoing = !ht.done();
158                         }
159
160                         if ( vt ) {
161                                 c = this._$clip.height();
162                                 v = this._getViewHeight();
163
164                                 if ( (( this._sy === 0 && speedY > 0 ) ||
165                                         ( this._sy === -(v - c) && speedY < 0 )) &&
166                                                 v > c ) {
167                                         return;
168                                 }
169
170                                 vt.start( this._sy, speedY,
171                                         duration, (v > c) ? -(v - c) : 0, 0 );
172                                 keepGoing = keepGoing || !vt.done();
173                         }
174
175                         if ( keepGoing ) {
176                                 this._timerID = setTimeout( this._timerCB, this._timerInterval );
177                         } else {
178                                 this._stopMScroll();
179                         }
180                 },
181
182                 _stopMScroll: function () {
183                         if ( this._timerID ) {
184                                 this._$clip.trigger( this.options.stopEventName );
185                                 clearTimeout( this._timerID );
186                         }
187                         this._timerID = 0;
188
189                         if ( this._vTracker ) {
190                                 this._vTracker.reset();
191                         }
192
193                         if ( this._hTracker ) {
194                                 this._hTracker.reset();
195                         }
196
197                         this._hideScrollBars();
198                         this._hideOverflowIndicator();
199                 },
200
201                 _handleMomentumScroll: function () {
202                         var keepGoing = false,
203                                 x = 0,
204                                 y = 0,
205                                 scroll_height = 0,
206                                 self = this,
207                                 end_effect = function ( dir ) {
208                                         setTimeout( function () {
209                                                 self._effect_dir = dir;
210                                                 self._setEndEffect( "in" );
211                                         }, 100 );
212
213                                         setTimeout( function () {
214                                                 self._setEndEffect( "out" );
215                                         }, 350 );
216                                 },
217                                 vt = this._vTracker,
218                                 ht = this._hTracker;
219
220                         if ( this._outerScrolling ) {
221                                 return;
222                         }
223
224                         if ( vt ) {
225                                 vt.update( this.options.overshootEnable );
226                                 y = vt.getPosition();
227                                 keepGoing = !vt.done();
228
229                                 if ( vt.getRemained() > this.options.overshootDuration ) {
230                                         scroll_height = this._getViewHeight() - this._$clip.height();
231
232                                         if ( !vt.isAvail() ) {
233                                                 if ( this._speedY > 0 ) {
234                                                         this._outerScroll( vt.getRemained() / 3, scroll_height );
235                                                 } else {
236                                                         this._outerScroll( y - vt.getRemained() / 3, scroll_height );
237                                                 }
238                                         } else if ( vt.isMin() ) {
239                                                 this._outerScroll( y - vt.getRemained() / 3, scroll_height );
240
241                                                 if ( scroll_height > 0 ) {
242                                                         end_effect( 1 );
243                                                 }
244                                         } else if ( vt.isMax() ) {
245                                                 this._outerScroll( vt.getRemained() / 3, scroll_height );
246
247                                                 if ( scroll_height > 0 ) {
248                                                         end_effect( 0 );
249                                                 }
250                                         }
251                                 }
252                         }
253
254                         if ( ht ) {
255                                 ht.update( this.options.overshootEnable );
256                                 x = ht.getPosition();
257                                 keepGoing = keepGoing || !ht.done();
258                         }
259
260                         this._setScrollPosition( x, y );
261                         this._$clip.trigger( this.options.updateEventName,
262                                         [ { x: x, y: y } ] );
263
264                         if ( keepGoing ) {
265                                 this._timerID = setTimeout( this._timerCB, this._timerInterval );
266                         } else {
267                                 this._stopMScroll();
268                         }
269                 },
270
271                 _setElementTransform: function ( $ele, x, y, duration ) {
272                         var translate,
273                                 transition;
274
275                         if ( !duration || duration === undefined ) {
276                                 transition = "none";
277                         } else {
278                                 transition =  "-webkit-transform " + duration / 1000 + "s ease-out";
279                         }
280
281                         if ( $.support.cssTransform3d ) {
282                                 translate = "translate3d(" + x + "," + y + ", 0px)";
283                         } else {
284                                 translate = "translate(" + x + "," + y + ")";
285                         }
286
287                         $ele.css({
288                                 "-moz-transform": translate,
289                                 "-webkit-transform": translate,
290                                 "-ms-transform": translate,
291                                 "-o-transform": translate,
292                                 "transform": translate,
293                                 "-webkit-transition": transition
294                         });
295                 },
296
297                 _setEndEffect: function ( dir ) {
298                         var scroll_height = this._getViewHeight() - this._$clip.height();
299
300                         if ( this._softkeyboard ) {
301                                 if ( this._effect_dir ) {
302                                         this._outerScroll( -scroll_height - this._softkeyboardHeight,
303                                                         scroll_height );
304                                 } else {
305                                         this._outerScroll( this._softkeyboardHeight, scroll_height );
306                                 }
307                                 return;
308                         }
309
310                         if ( dir === "in" ) {
311                                 if ( this._endEffect ) {
312                                         return;
313                                 }
314
315                                 this._endEffect = true;
316                                 this._setOverflowIndicator( this._effect_dir );
317                                 this._showOverflowIndicator();
318                         } else if ( dir === "out" ) {
319                                 if ( !this._endEffect ) {
320                                         return;
321                                 }
322
323                                 this._endEffect = false;
324                         } else {
325                                 this._endEffect = false;
326                                 this._setOverflowIndicator();
327                                 this._showOverflowIndicator();
328                         }
329                 },
330
331                 _setCalibration: function ( x, y ) {
332                         if ( this.options.overshootEnable ) {
333                                 this._sx = x;
334                                 this._sy = y;
335                                 return;
336                         }
337
338                         var $v = this._$view,
339                                 $c = this._$clip,
340                                 dirLock = this._directionLock,
341                                 scroll_height = 0,
342                                 scroll_width = 0;
343
344                         if ( dirLock !== "y" && this._hTracker ) {
345                                 scroll_width = $v.width() - $c.width();
346
347                                 if ( x >= 0 ) {
348                                         this._sx = 0;
349                                 } else if ( x < -scroll_width ) {
350                                         this._sx = -scroll_width;
351                                 } else {
352                                         this._sx = x;
353                                 }
354
355                                 if ( scroll_width < 0 ) {
356                                         this._sx = 0;
357                                 }
358                         }
359
360                         if ( dirLock !== "x" && this._vTracker ) {
361                                 scroll_height = this._getViewHeight() - $c.height();
362
363                                 if ( y > 0 ) {
364                                         this._sy = 0;
365
366                                         if ( this._didDrag && scroll_height > 0 ) {
367                                                 this._effect_dir = 0;
368                                                 this._setEndEffect( "in" );
369                                         }
370                                 } else if ( y < -scroll_height ) {
371                                         this._sy = -scroll_height;
372
373                                         if ( this._didDrag && scroll_height > 0 ) {
374                                                 this._effect_dir = 1;
375                                                 this._setEndEffect( "in" );
376                                         }
377                                 } else {
378                                         if ( this._endEffect && this._sy !== y ) {
379                                                 this._setEndEffect();
380                                         }
381
382                                         this._sy = y;
383                                 }
384
385                                 if ( scroll_height < 0 ) {
386                                         this._sy = 0;
387                                 }
388                         }
389                 },
390
391                 _setScrollPosition: function ( x, y, duration ) {
392                         var $v = this._$view,
393                                 sm = this.options.scrollMethod,
394                                 $vsb = this._$vScrollBar,
395                                 $hsb = this._$hScrollBar,
396                                 $sbt;
397
398                         this._setCalibration( x, y );
399
400                         x = this._sx;
401                         y = this._sy;
402
403                         if ( sm === "translate" ) {
404                                 this._setElementTransform( $v, x + "px", y + "px", duration );
405                         } else {
406                                 $v.css( {left: x + "px", top: y + "px"} );
407                         }
408
409                         if ( $vsb ) {
410                                 $sbt = $vsb.find(".ui-scrollbar-thumb");
411
412                                 if ( sm === "translate" ) {
413                                         this._setElementTransform( $sbt, "0px",
414                                                 -y / this._getViewHeight() * $sbt.parent().height() + "px",
415                                                 duration );
416                                 } else {
417                                         $sbt.css( "top", -y / this._getViewHeight() * 100 + "%" );
418                                 }
419                         }
420
421                         if ( $hsb ) {
422                                 $sbt = $hsb.find(".ui-scrollbar-thumb");
423
424                                 if ( sm === "translate" ) {
425                                         this._setElementTransform( $sbt,
426                                                 -x / $v.width() * $sbt.parent().width() + "px", "0px",
427                                                 duration);
428                                 } else {
429                                         $sbt.css("left", -x / $v.width() * 100 + "%");
430                                 }
431                         }
432                 },
433
434                 _outerScroll: function ( y, scroll_height ) {
435                         var self = this,
436                                 top = $( window ).scrollTop() - window.screenTop,
437                                 sy = 0,
438                                 duration = this.options.snapbackDuration,
439                                 start = getCurrentTime(),
440                                 tfunc;
441
442                         if ( !this.options.outerScrollEnable ) {
443                                 return;
444                         }
445
446                         if ( this._$clip.jqmData("scroll") !== "y" ) {
447                                 return;
448                         }
449
450                         if ( this._outerScrolling ) {
451                                 return;
452                         }
453
454                         if ( y > 0 ) {
455                                 sy = ( window.screenTop ? window.screenTop : -y );
456                         } else if ( y < -scroll_height ) {
457                                 sy = -y - scroll_height;
458                         } else {
459                                 return;
460                         }
461
462                         tfunc = function () {
463                                 var elapsed = getCurrentTime() - start;
464
465                                 if ( elapsed >= duration ) {
466                                         window.scrollTo( 0, top + sy );
467                                         self._outerScrolling = undefined;
468
469                                         self._stopMScroll();
470                                 } else {
471                                         ec = $.easing.easeOutQuad( elapsed / duration,
472                                                         elapsed, 0, 1, duration );
473
474                                         window.scrollTo( 0, top + ( sy * ec ) );
475                                         self._outerScrolling = setTimeout( tfunc, self._timerInterval );
476                                 }
477                         };
478                         this._outerScrolling = setTimeout( tfunc, self._timerInterval );
479                 },
480
481                 _scrollTo: function ( x, y, duration ) {
482                         var self = this,
483                                 start = getCurrentTime(),
484                                 efunc = $.easing.easeOutQuad,
485                                 sx = this._sx,
486                                 sy = this._sy,
487                                 dx = x - sx,
488                                 dy = y - sy,
489                                 tfunc;
490
491                         x = -x;
492                         y = -y;
493
494                         tfunc = function () {
495                                 var elapsed = getCurrentTime() - start,
496                                     ec;
497
498                                 if ( elapsed >= duration ) {
499                                         self._timerID = 0;
500                                         self._setScrollPosition( x, y );
501                                 } else {
502                                         ec = efunc( elapsed / duration, elapsed, 0, 1, duration );
503
504                                         self._setScrollPosition( sx + ( dx * ec ), sy + ( dy * ec ) );
505                                         self._timerID = setTimeout( tfunc, self._timerInterval );
506                                 }
507                         };
508
509                         this._timerID = setTimeout( tfunc, this._timerInterval );
510                 },
511
512                 scrollTo: function ( x, y, duration ) {
513                         this._stopMScroll();
514                         this._didDrag = false;
515
516                         if ( !duration || this.options.scrollMethod === "translate" ) {
517                                 this._setScrollPosition( x, y, duration );
518                         } else {
519                                 this._scrollTo( x, y, duration );
520                         }
521                 },
522
523                 getScrollPosition: function () {
524                         return { x: -this._sx, y: -this._sy };
525                 },
526
527                 skipDragging: function ( value ) {
528                         this._skip_dragging = value;
529                 },
530
531                 _getScrollHierarchy: function () {
532                         var svh = [],
533                                 d;
534
535                         this._$clip.parents( ".ui-scrollview-clip").each( function () {
536                                 d = $( this ).jqmData("scrollview");
537                                 if ( d ) {
538                                         svh.unshift( d );
539                                 }
540                         } );
541                         return svh;
542                 },
543
544                 _getAncestorByDirection: function ( dir ) {
545                         var svh = this._getScrollHierarchy(),
546                                 n = svh.length,
547                                 sv,
548                                 svdir;
549
550                         while ( 0 < n-- ) {
551                                 sv = svh[n];
552                                 svdir = sv.options.direction;
553
554                                 if (!svdir || svdir === dir) {
555                                         return sv;
556                                 }
557                         }
558                         return null;
559                 },
560
561                 _handleDragStart: function ( e, ex, ey ) {
562                         this._stopMScroll();
563
564                         this._didDrag = false;
565                         this._skip_dragging = false;
566
567                         var target = $( e.target ),
568                                 self = this,
569                                 $c = this._$clip,
570                                 svdir = this.options.direction;
571
572                         /* should prevent the default behavior when click the button */
573                         this._is_button = target.is( '.ui-btn' ) ||
574                                         target.is( '.ui-btn-text' ) ||
575                                         target.is( '.ui-btn-inner' ) ||
576                                         target.is( '.ui-btn-inner .ui-icon' );
577
578                         /* should prevent the default behavior when click the slider */
579                         if ( target.parents('.ui-slider').length || target.is('.ui-slider') ) {
580                                 this._skip_dragging = true;
581                                 return;
582                         }
583
584                         if ( target.is('textarea') ) {
585                                 target.bind( "scroll", function () {
586                                         self._skip_dragging = true;
587                                         target.unbind("scroll");
588                                 });
589                         }
590
591                         /*
592                          * We need to prevent the default behavior to
593                          * suppress accidental selection of text, etc.
594                          */
595                         this._is_inputbox = target.is(':input') ||
596                                         target.parents(':input').length > 0;
597
598                         if ( this._is_inputbox ) {
599                                 target.one( "resize.scrollview", function () {
600                                         if ( ey > $c.height() ) {
601                                                 self.scrollTo( -ex, self._sy - ey + $c.height(),
602                                                         self.options.snapbackDuration );
603                                         }
604                                 });
605                         }
606
607                         if ( this.options.eventType === "mouse" && !this._is_inputbox && !this._is_button ) {
608                                 e.preventDefault();
609                         }
610
611                         this._lastX = ex;
612                         this._lastY = ey;
613                         this._startY = ey;
614                         this._doSnapBackX = false;
615                         this._doSnapBackY = false;
616                         this._speedX = 0;
617                         this._speedY = 0;
618                         this._directionLock = "";
619
620                         this._lastMove = 0;
621                         this._enableTracking();
622
623                         this._set_scrollbar_size();
624                 },
625
626                 _propagateDragMove: function ( sv, e, ex, ey, dir ) {
627                         this._hideScrollBars();
628                         this._hideOverflowIndicator();
629                         this._disableTracking();
630                         sv._handleDragStart( e, ex, ey );
631                         sv._directionLock = dir;
632                         sv._didDrag = this._didDrag;
633                 },
634
635                 _handleDragMove: function ( e, ex, ey ) {
636                         if ( this._skip_dragging ) {
637                                 return;
638                         }
639
640                         if ( !this._dragging ) {
641                                 return;
642                         }
643
644                         if ( !this._is_inputbox && !this._is_button ) {
645                                 e.preventDefault();
646                         }
647
648                         var mt = this.options.moveThreshold,
649                                 dx = ex - this._lastX,
650                                 dy = ey - this._lastY,
651                                 svdir = this.options.direction,
652                                 dir = null,
653                                 x,
654                                 y,
655                                 sv,
656                                 scope,
657                                 newX,
658                                 newY,
659                                 dirLock;
660
661                         this._lastMove = getCurrentTime();
662
663                         if ( !this._directionLock ) {
664                                 x = Math.abs( dx );
665                                 y = Math.abs( dy );
666
667                                 if ( x < mt && y < mt ) {
668                                         return false;
669                                 }
670
671                                 if ( x < y && (x / y) < 0.5 ) {
672                                         dir = "y";
673                                 } else if ( x > y && (y / x) < 0.5 ) {
674                                         dir = "x";
675                                 }
676
677                                 if ( svdir && dir && svdir !== dir ) {
678                                         /*
679                                          * This scrollview can't handle the direction the user
680                                          * is attempting to scroll. Find an ancestor scrollview
681                                          * that can handle the request.
682                                          */
683
684                                         sv = this._getAncestorByDirection( dir );
685                                         if ( sv ) {
686                                                 this._propagateDragMove( sv, e, ex, ey, dir );
687                                                 return false;
688                                         }
689                                 }
690
691                                 this._directionLock = svdir || (dir || "none");
692                         }
693
694                         newX = this._sx;
695                         newY = this._sy;
696                         dirLock = this._directionLock;
697
698                         if ( dirLock !== "y" && this._hTracker ) {
699                                 x = this._sx;
700                                 this._speedX = dx;
701                                 newX = x + dx;
702
703                                 this._doSnapBackX = false;
704
705                                 scope = ( newX > 0 || newX < this._maxX );
706
707                                 if ( scope && dirLock === "x" ) {
708                                         sv = this._getAncestorByDirection("x");
709                                         if ( sv ) {
710                                                 this._setScrollPosition( newX > 0 ?
711                                                                 0 : this._maxX, newY );
712                                                 this._propagateDragMove( sv, e, ex, ey, dir );
713                                                 return false;
714                                         }
715
716                                         newX = x + ( dx / 2 );
717                                         this._doSnapBackX = true;
718                                 }
719                         }
720
721                         if ( dirLock !== "x" && this._vTracker ) {
722                                 if ( Math.abs( this._startY - ey ) < mt && dirLock !== "xy" ) {
723                                         return;
724                                 }
725
726                                 y = this._sy;
727                                 this._speedY = dy;
728                                 newY = y + dy;
729
730                                 this._doSnapBackY = false;
731
732                                 scope = ( newY > 0 || newY < this._maxY );
733
734                                 if ( scope && dirLock === "y" ) {
735                                         sv = this._getAncestorByDirection("y");
736                                         if ( sv ) {
737                                                 this._setScrollPosition( newX,
738                                                                 newY > 0 ? 0 : this._maxY );
739                                                 this._propagateDragMove( sv, e, ex, ey, dir );
740                                                 return false;
741                                         }
742
743                                         newY = y + ( dy / 2 );
744                                         this._doSnapBackY = true;
745                                 }
746                         }
747
748                         if ( this.options.overshootEnable === false ) {
749                                 this._doSnapBackX = false;
750                                 this._doSnapBackY = false;
751                         }
752
753                         this._lastX = ex;
754                         this._lastY = ey;
755
756                         this._setScrollPosition( newX, newY );
757
758                         if ( this._didDrag === false ) {
759                                 this._didDrag = true;
760                                 this._showScrollBars();
761                                 this._showOverflowIndicator();
762
763                                 this._$clip.parents(".ui-scrollview-clip").each( function () {
764                                         $( this ).scrollview( "skipDragging", true );
765                                 } );
766                         }
767                 },
768
769                 _handleDragStop: function ( e ) {
770                         var self = this;
771
772                         if ( this._skip_dragging ) {
773                                 return;
774                         }
775
776                         var l = this._lastMove,
777                                 t = getCurrentTime(),
778                                 doScroll = (l && (t - l) <= this.options.moveIntervalThreshold),
779                                 sx = ( this._hTracker && this._speedX && doScroll ) ?
780                                                 this._speedX : ( this._doSnapBackX ? 1 : 0 ),
781                                 sy = ( this._vTracker && this._speedY && doScroll ) ?
782                                                 this._speedY : ( this._doSnapBackY ? 1 : 0 ),
783                                 svdir = this.options.direction,
784                                 x,
785                                 y;
786
787                         if ( sx || sy ) {
788                                 if ( !this._setGestureScroll( sx, sy ) ) {
789                                         this._startMScroll( sx, sy );
790                                 }
791                         } else {
792                                 this._hideScrollBars();
793                                 this._hideOverflowIndicator();
794                         }
795
796                         this._disableTracking();
797
798                         if ( this._endEffect ) {
799                                 setTimeout( function () {
800                                         self._setEndEffect( "out" );
801                                         self._hideScrollBars();
802                                         self._hideOverflowIndicator();
803                                 }, 300 );
804                         }
805
806                         return !this._didDrag;
807                 },
808
809                 _setGestureScroll: function ( sx, sy ) {
810                         var self = this,
811                                 reset = function () {
812                                         clearTimeout( self._gesture_timer );
813                                         self._gesture_dir = 0;
814                                         self._gesture_count = 0;
815                                         self._gesture_timer = undefined;
816                                 },
817                                 direction = {
818                                         top: 0,
819                                         bottom: 1,
820                                         left: 2,
821                                         right: 3
822                                 };
823
824                         if ( !sy && !sx ) {
825                                 return false;
826                         }
827
828                         if ( Math.abs( sx ) > Math.abs( sy ) ) {
829                                 dir = sx > 0 ? direction.left : direction.right;
830                         } else {
831                                 dir = sy > 0 ? direction.top : direction.bottom;
832                         }
833
834                         if ( !this._gesture_timer ) {
835                                 this._gesture_count = 1;
836                                 this._gesture_dir = dir;
837
838                                 this._gesture_timer = setTimeout( function () {
839                                         reset();
840                                 }, 1000 );
841
842                                 return false;
843                         }
844
845                         if ( this._gesture_dir !== dir ) {
846                                 reset();
847                                 return false;
848                         }
849
850                         this._gesture_count++;
851
852                         if ( this._gesture_count === 3 ) {
853                                 switch ( dir ) {
854                                 case direction.top:
855                                         this.scrollTo( this._sx, 0, this.options.overshootDuration );
856                                         break;
857                                 case direction.bottom:
858                                         this.scrollTo( this._sx, -( this._getViewHeight() - this._$clip.height() ),
859                                                         this.options.overshootDuration );
860                                         break;
861                                 case direction.left:
862                                         this.scrollTo( 0, this._sy, this.options.overshootDuration );
863                                         break;
864                                 case direction.right:
865                                         this.scrollTo( -( this._$view.width() - this._$clip.width() ), this._sy,
866                                                         this.options.overshootDuration );
867                                         break;
868                                 }
869
870                                 reset();
871                                 this._didDrag = true;
872
873                                 return true;
874                         }
875
876                         return false;
877                 },
878
879                 _enableTracking: function () {
880                         this._dragging = true;
881                 },
882
883                 _disableTracking: function () {
884                         this._dragging = false;
885                 },
886
887                 _showScrollBars: function ( interval ) {
888                         var vclass = "ui-scrollbar-visible",
889                                 self = this;
890
891                         if ( !this.options.showScrollBars ) {
892                                 return;
893                         }
894                         if ( this._scrollbar_showed ) {
895                                 return;
896                         }
897
898                         if ( this._$vScrollBar ) {
899                                 this._$vScrollBar.addClass( vclass );
900                         }
901                         if ( this._$hScrollBar ) {
902                                 this._$hScrollBar.addClass( vclass );
903                         }
904
905                         this._scrollbar_showed = true;
906
907                         if ( interval ) {
908                                 setTimeout( function () {
909                                         self._hideScrollBars();
910                                 }, interval );
911                         }
912                 },
913
914                 _hideScrollBars: function () {
915                         var vclass = "ui-scrollbar-visible";
916
917                         if ( !this.options.showScrollBars ) {
918                                 return;
919                         }
920                         if ( !this._scrollbar_showed ) {
921                                 return;
922                         }
923
924                         if ( this._$vScrollBar ) {
925                                 this._$vScrollBar.removeClass( vclass );
926                         }
927                         if ( this._$hScrollBar ) {
928                                 this._$hScrollBar.removeClass( vclass );
929                         }
930
931                         this._scrollbar_showed = false;
932                 },
933
934                 _setOverflowIndicator: function ( dir ) {
935                         if ( dir === 1 ) {
936                                 this._opacity_top = "0";
937                                 this._opacity_bottom = "0.8";
938                         } else if ( dir === 0 ) {
939                                 this._opacity_top = "0.8";
940                                 this._opacity_bottom = "0";
941                         } else {
942                                 this._opacity_top = "0.5";
943                                 this._opacity_bottom = "0.5";
944                         }
945                 },
946
947                 _showOverflowIndicator: function () {
948                         if ( !this.options.overflowEnable || !this._overflowAvail || this._softkeyboard ) {
949                                 return;
950                         }
951
952                         this._overflow_top.animate( { opacity: this._opacity_top }, 300 );
953                         this._overflow_bottom.animate( { opacity: this._opacity_bottom }, 300 );
954
955                         this._overflow_showed = true;
956                 },
957
958                 _hideOverflowIndicator: function () {
959                         if ( !this.options.overflowEnable || !this._overflowAvail || this._softkeyboard ) {
960                                 return;
961                         }
962
963                         if ( this._overflow_showed === false ) {
964                                 return;
965                         }
966
967                         this._overflow_top.animate( { opacity: 0 }, 300 );
968                         this._overflow_bottom.animate( { opacity: 0 }, 300 );
969
970                         this._overflow_showed = false;
971                         this._setOverflowIndicator();
972                 },
973
974                 _add_event: function () {
975                         var self = this,
976                                 $c = this._$clip,
977                                 $v = this._$view;
978
979                         if ( this.options.eventType === "mouse" ) {
980                                 this._dragEvt = "mousedown mousemove mouseup click mousewheel";
981
982                                 this._dragCB = function ( e ) {
983                                         switch ( e.type ) {
984                                         case "mousedown":
985                                                 return self._handleDragStart( e,
986                                                                 e.clientX, e.clientY );
987
988                                         case "mousemove":
989                                                 return self._handleDragMove( e,
990                                                                 e.clientX, e.clientY );
991
992                                         case "mouseup":
993                                                 return self._handleDragStop( e );
994
995                                         case "click":
996                                                 return !self._didDrag;
997
998                                         case "mousewheel":
999                                                 var old = self.getScrollPosition();
1000                                                 self.scrollTo( -old.x,
1001                                                         -(old.y - e.originalEvent.wheelDelta) );
1002                                                 break;
1003                                         }
1004                                 };
1005                         } else {
1006                                 this._dragEvt = "touchstart touchmove touchend click";
1007
1008                                 this._dragCB = function ( e ) {
1009                                         var touches = e.originalEvent.touches;
1010
1011                                         switch ( e.type ) {
1012                                         case "touchstart":
1013                                                 if ( touches.length != 1) {
1014                                                         return;
1015                                                 }
1016
1017                                                 return self._handleDragStart( e,
1018                                                                 touches[0].pageX, touches[0].pageY );
1019
1020                                         case "touchmove":
1021                                                 if ( touches.length != 1) {
1022                                                         return;
1023                                                 }
1024
1025                                                 return self._handleDragMove( e,
1026                                                                 touches[0].pageX, touches[0].pageY );
1027
1028                                         case "touchend":
1029                                                 if ( touches.length != 0) {
1030                                                         return;
1031                                                 }
1032
1033                                                 return self._handleDragStop( e );
1034
1035                                         case "click":
1036                                                 return !self._didDrag;
1037                                         }
1038                                 };
1039                         }
1040
1041                         $v.bind( this._dragEvt, this._dragCB );
1042
1043                         $v.bind( "keydown", function ( e ) {
1044                                 var elem,
1045                                         elem_top,
1046                                         scroll_top = $( window ).scrollTop() - window.screenTop,
1047                                         screen_h;
1048
1049                                 if ( e.keyCode == 9 ) {
1050                                         return false;
1051                                 }
1052
1053                                 elem = $c.find(".ui-focus");
1054
1055                                 if ( elem === undefined ) {
1056                                         return;
1057                                 }
1058
1059                                 elem_top = elem.offset().top - scroll_top;
1060                                 screen_h = $c.offset().top + $c.height() - elem.height();
1061
1062                                 if ( self._softkeyboard ) {
1063                                         screen_h -= self._softkeyboardHeight;
1064                                 }
1065
1066                                 if ( ( elem_top < $c.offset().top ) || ( elem_top > screen_h ) ) {
1067                                         self.scrollTo( 0, self._sy -
1068                                                         ( elem_top - $c.offset().top - elem.height() ) );
1069                                 }
1070
1071                                 return;
1072                         });
1073
1074                         $v.bind( "keyup", function ( e ) {
1075                                 var input,
1076                                         elem,
1077                                         elem_top,
1078                                         scroll_top = $( window ).scrollTop() - window.screenTop,
1079                                         screen_h;
1080
1081                                 if ( e.keyCode != 9 ) {
1082                                         return;
1083                                 }
1084
1085                                 /* Tab Key */
1086
1087                                 input = $( this ).find(":input");
1088
1089                                 for ( i = 0; i < input.length; i++ ) {
1090                                         if ( !$( input[i] ).hasClass("ui-focus") ) {
1091                                                 continue;
1092                                         }
1093
1094                                         if ( i + 1 == input.length ) {
1095                                                 elem = $( input[0] );
1096                                         } else {
1097                                                 elem = $( input[i + 1] );
1098                                         }
1099
1100                                         elem_top = elem.offset().top - scroll_top;
1101                                         screen_h = $c.offset().top + $c.height() - elem.height();
1102
1103                                         if ( self._softkeyboard ) {
1104                                                 screen_h -= self._softkeyboardHeight;
1105                                         }
1106
1107                                         if ( ( elem_top < 0 ) || ( elem_top > screen_h ) ) {
1108                                                 self.scrollTo( 0, self._sy - elem_top +
1109                                                         elem.height() + $c.offset().top, 0);
1110                                         }
1111
1112                                         elem.focus();
1113
1114                                         break;
1115                                 }
1116
1117                                 return false;
1118                         });
1119
1120                         $c.bind( "updatelayout", function ( e ) {
1121                                 var sy,
1122                                         vh,
1123                                         view_h = self._getViewHeight();
1124
1125                                 if ( !$c.height() || !view_h ) {
1126                                         self.scrollTo( 0, 0, 0 );
1127                                         return;
1128                                 }
1129
1130                                 sy = $c.height() - view_h;
1131                                 vh = view_h - self._view_height;
1132
1133                                 self._view_height = view_h;
1134
1135                                 if ( vh == 0 || vh > $c.height() / 2 ) {
1136                                         return;
1137                                 }
1138
1139                                 if ( sy > 0 ) {
1140                                         self.scrollTo( 0, 0, 0 );
1141                                 } else if ( self._sy - sy <= -vh ) {
1142                                         self.scrollTo( 0, self._sy,
1143                                                 self.options.snapbackDuration );
1144                                 } else if ( self._sy - sy <= vh + self.options.moveThreshold ) {
1145                                         self.scrollTo( 0, sy,
1146                                                 self.options.snapbackDuration );
1147                                 }
1148                         });
1149
1150                         $( window ).bind( "resize", function ( e ) {
1151                                 var focused,
1152                                         view_h = self._getViewHeight();
1153
1154                                 if ( $(".ui-page-active").get(0) !== $c.closest(".ui-page").get(0) ) {
1155                                         return;
1156                                 }
1157
1158                                 if ( !$c.height() || !view_h ) {
1159                                         return;
1160                                 }
1161
1162                                 focused = $c.find(".ui-focus");
1163
1164                                 if ( focused ) {
1165                                         focused.trigger("resize.scrollview");
1166                                 }
1167
1168                                 /* calibration - after triggered throttledresize */
1169                                 setTimeout( function () {
1170                                         if ( self._sy < $c.height() - self._getViewHeight() ) {
1171                                                 self.scrollTo( 0, $c.height() - self._getViewHeight(),
1172                                                         self.options.overshootDuration );
1173                                         }
1174                                 }, 260 );
1175
1176                                 self._view_height = view_h;
1177                         });
1178
1179                         $( window ).bind( "vmouseout", function ( e ) {
1180                                 var drag_stop = false;
1181
1182                                 if ( $(".ui-page-active").get(0) !== $c.closest(".ui-page").get(0) ) {
1183                                         return;
1184                                 }
1185
1186                                 if ( !self._dragging ) {
1187                                         return;
1188                                 }
1189
1190                                 if ( e.pageX < 0 || e.pageX > $( window ).width() ) {
1191                                         drag_stop = true;
1192                                 }
1193
1194                                 if ( e.pageY < 0 || e.pageY > $( window ).height() ) {
1195                                         drag_stop = true;
1196                                 }
1197
1198                                 if ( drag_stop ) {
1199                                         self._hideScrollBars();
1200                                         self._hideOverflowIndicator();
1201                                         self._disableTracking();
1202                                 }
1203                         });
1204
1205                         this._softkeyboard = false;
1206                         this._softkeyboardHeight = 0;
1207
1208                         window.addEventListener( "softkeyboardchange", function ( e ) {
1209                                 if ( $(".ui-page-active").get(0) !== $c.closest(".ui-page").get(0) ) {
1210                                         return;
1211                                 }
1212
1213                                 self._softkeyboard = ( e.state === "on" ? true : false );
1214                                 self._softkeyboardHeight = parseInt( e.height ) *
1215                                                 ( $( window ).width() / window.screen.availWidth );
1216                         });
1217
1218                         $c.closest(".ui-page")
1219                                 .bind( "pageshow", function ( e ) {
1220                                         /* should be called after pagelayout */
1221                                         setTimeout( function () {
1222                                                 self._view_height = self._getViewHeight();
1223                                                 self._set_scrollbar_size();
1224                                                 self._setScrollPosition( self._sx, self._sy );
1225                                                 self._showScrollBars( 2000 );
1226                                         }, 0 );
1227                                 });
1228                 },
1229
1230                 _add_scrollbar: function () {
1231                         var $c = this._$clip,
1232                                 prefix = "<div class=\"ui-scrollbar ui-scrollbar-",
1233                                 suffix = "\"><div class=\"ui-scrollbar-track\"><div class=\"ui-scrollbar-thumb\"></div></div></div>";
1234
1235                         if ( !this.options.showScrollBars ) {
1236                                 return;
1237                         }
1238
1239                         if ( this._vTracker ) {
1240                                 $c.append( prefix + "y" + suffix );
1241                                 this._$vScrollBar = $c.children(".ui-scrollbar-y");
1242                         }
1243                         if ( this._hTracker ) {
1244                                 $c.append( prefix + "x" + suffix );
1245                                 this._$hScrollBar = $c.children(".ui-scrollbar-x");
1246                         }
1247
1248                         this._scrollbar_showed = false;
1249                 },
1250
1251                 _add_scroll_jump: function () {
1252                         var $c = this._$clip,
1253                                 self = this,
1254                                 top_btn,
1255                                 left_btn;
1256
1257                         if ( !this.options.scrollJump ) {
1258                                 return;
1259                         }
1260
1261                         if ( this._vTracker ) {
1262                                 top_btn = $( '<div class="ui-scroll-jump-top-bg">' +
1263                                                 '<div data-role="button" data-inline="true" data-icon="scrolltop" data-style="box"></div></div>' );
1264                                 $c.append( top_btn ).trigger("create");
1265
1266                                 top_btn.bind( "vclick", function () {
1267                                         self.scrollTo( 0, 0, self.options.overshootDuration );
1268                                 } );
1269                         }
1270
1271                         if ( this._hTracker ) {
1272                                 left_btn = $( '<div class="ui-scroll-jump-left-bg">' +
1273                                                 '<div data-role="button" data-inline="true" data-icon="scrollleft" data-style="box"></div></div>' );
1274                                 $c.append( left_btn ).trigger("create");
1275
1276                                 left_btn.bind( "vclick", function () {
1277                                         self.scrollTo( 0, 0, self.options.overshootDuration );
1278                                 } );
1279                         }
1280                 },
1281
1282                 _add_overflow_indicator: function () {
1283                         if ( !this.options.overflowEnable ) {
1284                                 return;
1285                         }
1286
1287                         this._overflow_top = $( '<div class="ui-overflow-indicator-top"></div>' );
1288                         this._overflow_bottom = $( '<div class="ui-overflow-indicator-bottom"></div>' );
1289
1290                         this._$clip.append( this._overflow_top );
1291                         this._$clip.append( this._overflow_bottom );
1292
1293                         this._opacity_top = "0.5";
1294                         this._opacity_bottom = "0.5";
1295                         this._overflow_showed = false;
1296                 },
1297
1298                 _set_scrollbar_size: function () {
1299                         var $c = this._$clip,
1300                                 $v = this._$view,
1301                                 cw = 0,
1302                                 vw = 0,
1303                                 ch = 0,
1304                                 vh = 0,
1305                                 thumb;
1306
1307                         if ( !this.options.showScrollBars ) {
1308                                 return;
1309                         }
1310
1311                         if ( this._hTracker ) {
1312                                 cw = $c.width();
1313                                 vw = $v.width();
1314                                 this._maxX = cw - vw;
1315
1316                                 if ( this._maxX > 0 ) {
1317                                         this._maxX = 0;
1318                                 }
1319                                 if ( this._$hScrollBar && vw ) {
1320                                         thumb = this._$hScrollBar.find(".ui-scrollbar-thumb");
1321                                         thumb.css( "width", (cw >= vw ? "0" :
1322                                                         (Math.floor(cw / vw * 100) || 1) + "%") );
1323                                 }
1324                         }
1325
1326                         if ( this._vTracker ) {
1327                                 ch = $c.height();
1328                                 vh = this._getViewHeight();
1329                                 this._maxY = ch - vh;
1330
1331                                 if ( this._maxY > 0 ) {
1332                                         this._maxY = 0;
1333                                 }
1334                                 if ( this._$vScrollBar && vh ) {
1335                                         thumb = this._$vScrollBar.find(".ui-scrollbar-thumb");
1336                                         thumb.css( "height", (ch >= vh ? "0" :
1337                                                         (Math.floor(ch / vh * 100) || 1) + "%") );
1338
1339                                         this._overflowAvail = !!thumb.height();
1340                                 }
1341                         }
1342                 }
1343         });
1344
1345         $.extend( MomentumTracker.prototype, {
1346                 start: function ( pos, speed, duration, minPos, maxPos ) {
1347                         var tstate = ( pos < minPos || pos > maxPos ) ?
1348                                         tstates.snapback : tstates.scrolling,
1349                                 pos_temp;
1350
1351                         this.state = ( speed !== 0 ) ? tstate : tstates.done;
1352                         this.pos = pos;
1353                         this.speed = speed;
1354                         this.duration = ( this.state === tstates.snapback ) ?
1355                                         this.options.snapbackDuration : duration;
1356                         this.minPos = minPos;
1357                         this.maxPos = maxPos;
1358
1359                         this.fromPos = ( this.state === tstates.snapback ) ? this.pos : 0;
1360                         pos_temp = ( this.pos < this.minPos ) ? this.minPos : this.maxPos;
1361                         this.toPos = ( this.state === tstates.snapback ) ? pos_temp : 0;
1362
1363                         this.startTime = getCurrentTime();
1364                 },
1365
1366                 reset: function () {
1367                         this.state = tstates.done;
1368                         this.pos = 0;
1369                         this.speed = 0;
1370                         this.minPos = 0;
1371                         this.maxPos = 0;
1372                         this.duration = 0;
1373                         this.remained = 0;
1374                 },
1375
1376                 update: function ( overshootEnable ) {
1377                         var state = this.state,
1378                                 cur_time = getCurrentTime(),
1379                                 duration = this.duration,
1380                                 elapsed =  cur_time - this.startTime,
1381                                 dx,
1382                                 x,
1383                                 didOverShoot;
1384
1385                         if ( state === tstates.done ) {
1386                                 return this.pos;
1387                         }
1388
1389                         elapsed = elapsed > duration ? duration : elapsed;
1390
1391                         this.remained = duration - elapsed;
1392
1393                         if ( state === tstates.scrolling || state === tstates.overshot ) {
1394                                 dx = this.speed *
1395                                         ( 1 - $.easing[this.easing]( elapsed / duration,
1396                                                                 elapsed, 0, 1, duration ) );
1397
1398                                 x = this.pos + dx;
1399
1400                                 didOverShoot = ( state === tstates.scrolling ) &&
1401                                         ( x < this.minPos || x > this.maxPos );
1402
1403                                 if ( didOverShoot ) {
1404                                         x = ( x < this.minPos ) ? this.minPos : this.maxPos;
1405                                 }
1406
1407                                 this.pos = x;
1408
1409                                 if ( state === tstates.overshot ) {
1410                                         if ( !overshootEnable ) {
1411                                                 this.state = tstates.done;
1412                                         }
1413                                         if ( elapsed >= duration ) {
1414                                                 this.state = tstates.snapback;
1415                                                 this.fromPos = this.pos;
1416                                                 this.toPos = ( x < this.minPos ) ?
1417                                                                 this.minPos : this.maxPos;
1418                                                 this.duration = this.options.snapbackDuration;
1419                                                 this.startTime = cur_time;
1420                                                 elapsed = 0;
1421                                         }
1422                                 } else if ( state === tstates.scrolling ) {
1423                                         if ( didOverShoot && overshootEnable ) {
1424                                                 this.state = tstates.overshot;
1425                                                 this.speed = dx / 2;
1426                                                 this.duration = this.options.overshootDuration;
1427                                                 this.startTime = cur_time;
1428                                         } else if ( elapsed >= duration ) {
1429                                                 this.state = tstates.done;
1430                                         }
1431                                 }
1432                         } else if ( state === tstates.snapback ) {
1433                                 if ( elapsed >= duration ) {
1434                                         this.pos = this.toPos;
1435                                         this.state = tstates.done;
1436                                 } else {
1437                                         this.pos = this.fromPos + (( this.toPos - this.fromPos ) *
1438                                                 $.easing[this.easing]( elapsed / duration,
1439                                                         elapsed, 0, 1, duration ));
1440                                 }
1441                         }
1442
1443                         return this.pos;
1444                 },
1445
1446                 done: function () {
1447                         return this.state === tstates.done;
1448                 },
1449
1450                 isMin: function () {
1451                         return this.pos === this.minPos;
1452                 },
1453
1454                 isMax: function () {
1455                         return this.pos === this.maxPos;
1456                 },
1457
1458                 isAvail: function () {
1459                         return !( this.minPos === this.maxPos );
1460                 },
1461
1462                 getRemained: function () {
1463                         return this.remained;
1464                 },
1465
1466                 getPosition: function () {
1467                         return this.pos;
1468                 }
1469         });
1470
1471         $( document ).bind( 'pagecreate create', function ( e ) {
1472                 var $page = $( e.target ),
1473                         content_scroll = $page.find(".ui-content").jqmData("scroll");
1474
1475                 /* content scroll */
1476                 if ( $.support.scrollview === undefined ) {
1477                         $.support.scrollview = true;
1478                 }
1479
1480                 if ( $.support.scrollview === true && content_scroll === undefined ) {
1481                         content_scroll = "y";
1482                 }
1483
1484                 if ( content_scroll !== "y" ) {
1485                         content_scroll = "none";
1486                 }
1487
1488                 $page.find(".ui-content").attr( "data-scroll", content_scroll );
1489
1490                 $page.find(":jqmData(scroll)").not(".ui-scrollview-clip").each( function () {
1491                         if ( $( this ).hasClass("ui-scrolllistview") ) {
1492                                 $( this ).scrolllistview();
1493                         } else {
1494                                 var st = $( this ).jqmData("scroll"),
1495                                         dir = st && ( st.search(/^[xy]/) !== -1 ) ? st : null,
1496                                         content = $(this).hasClass("ui-content"),
1497                                         opts;
1498
1499                                 if ( st === "none" ) {
1500                                         return;
1501                                 }
1502
1503                                 opts = {
1504                                         direction: dir || undefined,
1505                                         overflowEnable: content,
1506                                         scrollMethod: $( this ).jqmData("scroll-method") || undefined,
1507                                         scrollJump: $( this ).jqmData("scroll-jump") || undefined
1508                                 };
1509
1510                                 $( this ).scrollview( opts );
1511                         }
1512                 });
1513         });
1514
1515         $( document ).bind( 'pageshow', function ( e ) {
1516                 var $page = $( e.target ),
1517                         scroll = $page.find(".ui-content").jqmData("scroll");
1518
1519                 if ( scroll === "y" ) {
1520                         resizePageContentHeight( e.target );
1521                 }
1522         });
1523
1524 }( jQuery, window, document ) );
1525
1526 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
1527 } );
1528 //>>excludeEnd("jqmBuildExclude");