[TemporaryStorage] add files required for SDK build
[samples/web/TemporaryStorage.git] / tizen-web-ui-fw / latest / js / src / widgets / jquery.mobile.tizen.circularview.js
1
2 /* ***************************************************************************
3  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software" ),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  * ***************************************************************************
23  */
24
25 // most of following codes are derived from jquery.mobile.scrollview.js
26 (function ( $, window, document, undefined ) {
27
28         function circularNum( num, total ) {
29                 var n = num % total;
30                 if ( n < 0 ) {
31                         n = total + n;
32                 }
33                 return n;
34         }
35
36         function setElementTransform( $ele, x, y ) {
37                 var v = "translate3d( " + x + "," + y + ", 0px)";
38                 $ele.css({
39                         "-ms-transform": v,
40                         "-o-transform": v,
41                         "-moz-transform": v,
42                         "-webkit-transform": v,
43                         "transform": v
44                 } );
45         }
46
47         function MomentumTracker( options ) {
48                 this.options = $.extend( {}, options );
49                 this.easing = "easeOutQuad";
50                 this.reset();
51         }
52
53         var tstates = {
54                 scrolling : 0,
55                 done : 1
56         };
57
58         function getCurrentTime() {
59                 return Date.now();
60         }
61
62         $.extend( MomentumTracker.prototype, {
63                 start: function ( pos, speed, duration ) {
64                         this.state = ( speed != 0 ) ? tstates.scrolling : tstates.done;
65                         this.pos = pos;
66                         this.speed = speed;
67                         this.duration = duration;
68
69                         this.fromPos = 0;
70                         this.toPos = 0;
71
72                         this.startTime = getCurrentTime();
73                 },
74
75                 reset: function () {
76                         this.state = tstates.done;
77                         this.pos = 0;
78                         this.speed = 0;
79                         this.duration = 0;
80                 },
81
82                 update: function () {
83                         var state = this.state,
84                                 duration,
85                                 elapsed,
86                                 dx,
87                                 x;
88
89                         if ( state == tstates.done ) {
90                                 return this.pos;
91                         }
92
93                         duration = this.duration;
94                         elapsed = getCurrentTime() - this.startTime;
95                         elapsed = elapsed > duration ? duration : elapsed;
96
97                         dx = this.speed * ( 1 - $.easing[this.easing](elapsed / duration, elapsed, 0, 1, duration ) );
98
99                         x = this.pos + dx;
100                         this.pos = x;
101
102                         if ( elapsed >= duration ) {
103                                 this.state = tstates.done;
104                         }
105
106                         return this.pos;
107                 },
108
109                 done: function () {
110                         return this.state == tstates.done;
111                 },
112
113                 getPosition: function () {
114                         return this.pos;
115                 }
116         } );
117
118         jQuery.widget( "mobile.circularview", jQuery.mobile.widget, {
119                 options: {
120                         fps:                            60,
121
122                         scrollDuration:         2000,
123
124                         moveThreshold:          10,
125                         moveIntervalThreshold:  150,
126
127                         startEventName:         "scrollstart",
128                         updateEventName:        "scrollupdate",
129                         stopEventName:          "scrollstop",
130
131                         eventType:                      $.support.touch ? "touch" : "mouse",
132
133                         delayedClickSelector: "a, .ui-btn",
134                         delayedClickEnabled: false
135                 },
136
137                 _makePositioned: function ( $ele ) {
138                         if ( $ele.css( 'position' ) == 'static' ) {
139                                 $ele.css( 'position', 'relative' );
140                         }
141                 },
142
143                 _create: function () {
144                         var self = this;
145
146                         this._items = $( this.element ).jqmData('list');
147                         this._$clip = $( this.element ).addClass( "ui-scrollview-clip" );
148                         this._$clip.wrapInner( '<div class="ui-scrollview-view"></div>' );
149                         this._$view = $('.ui-scrollview-view', this._$clip );
150                         this._$list = $( 'ul', this._$clip );
151
152                         this._$clip.css( "overflow", "hidden" );
153                         this._makePositioned( this._$clip );
154
155                         this._$view.css( "overflow", "hidden" );
156                         this._tracker = new MomentumTracker( this.options );
157
158                         this._timerInterval = 1000 / this.options.fps;
159                         this._timerID = 0;
160
161                         this._timerCB = function () { self._handleMomentumScroll(); };
162
163                         this.refresh();
164
165                         this._addBehaviors();
166                 },
167
168                 reflow: function () {
169                         var xy = this.getScrollPosition();
170                         this.refresh();
171                         this.scrollTo( xy.x, xy.y );
172                 },
173
174                 refresh: function () {
175                         var itemsPerView;
176
177                         this._$clip.width( $(window).width() );
178                         this._clipWidth = this._$clip.width();
179                         this._$list.empty();
180                         this._$list.append(this._items[0]);
181                         this._itemWidth = $(this._items[0]).outerWidth();
182                         $(this._items[0]).detach();
183
184                         itemsPerView = this._clipWidth / this._itemWidth;
185                         itemsPerView = Math.ceil( itemsPerView * 10 ) / 10;
186                         this._itemsPerView = parseInt( itemsPerView, 10 );
187                         while ( this._itemsPerView + 1 > this._items.length ) {
188                                 $.merge( this._items, $(this._items).clone() );
189                         }
190                         this._rx = -this._itemWidth;
191                         this._sx = -this._itemWidth;
192                         this._setItems();
193                 },
194
195                 _startMScroll: function ( speedX, speedY ) {
196                         this._stopMScroll();
197
198                         var keepGoing = false,
199                                 duration = this.options.scrollDuration,
200                                 t = this._tracker,
201                                 c = this._clipWidth,
202                                 v = this._viewWidth;
203
204                         this._$clip.trigger( this.options.startEventName);
205
206                         t.start( this._rx, speedX, duration, (v > c ) ? -(v - c) : 0, 0 );
207                         keepGoing = !t.done();
208
209                         if ( keepGoing ) {
210                                 this._timerID = setTimeout( this._timerCB, this._timerInterval );
211                         } else {
212                                 this._stopMScroll();
213                         }
214                         //console.log( "startmscroll" + this._rx + "," + this._sx );
215                 },
216
217                 _stopMScroll: function () {
218                         if ( this._timerID ) {
219                                 this._$clip.trigger( this.options.stopEventName );
220                                 clearTimeout( this._timerID );
221                         }
222
223                         this._timerID = 0;
224
225                         if ( this._tracker ) {
226                                 this._tracker.reset();
227                         }
228                         //console.log( "stopmscroll" + this._rx + "," + this._sx );
229                 },
230
231                 _handleMomentumScroll: function () {
232                         var keepGoing = false,
233                                 v = this._$view,
234                                 x = 0,
235                                 y = 0,
236                                 t = this._tracker;
237
238                         if ( t ) {
239                                 t.update();
240                                 x = t.getPosition();
241
242                                 keepGoing = !t.done();
243
244                         }
245
246                         this._setScrollPosition( x, y );
247                         this._rx = x;
248
249                         this._$clip.trigger( this.options.updateEventName, [ { x: x, y: y } ] );
250
251                         if ( keepGoing ) {
252                                 this._timerID = setTimeout( this._timerCB, this._timerInterval );
253                         } else {
254                                 this._stopMScroll();
255                         }
256                 },
257
258                 _setItems: function () {
259                         var i,
260                                 $item;
261
262                         for ( i = -1; i < this._itemsPerView + 1; i++ ) {
263                                 $item = this._items[ circularNum( i, this._items.length ) ];
264                                 this._$list.append( $item );
265                         }
266                         setElementTransform( this._$view, this._sx + "px", 0 );
267                         this._$view.width( this._itemWidth * ( this._itemsPerView + 2 ) );
268                         this._viewWidth = this._$view.width();
269                 },
270
271                 _setScrollPosition: function ( x, y ) {
272                         var sx = this._sx,
273                                 dx = x - sx,
274                                 di = parseInt( dx / this._itemWidth, 10 ),
275                                 i,
276                                 idx,
277                                 $item;
278
279                         if ( di > 0 ) {
280                                 for ( i = 0; i < di; i++ ) {
281                                         this._$list.children().last().detach();
282                                         idx = -parseInt( ( sx / this._itemWidth ) + i + 3, 10 );
283                                         $item = this._items[ circularNum( idx, this._items.length ) ];
284                                         this._$list.prepend( $item );
285                                         //console.log( "di > 0 : " + idx );
286                                 }
287                         } else if ( di < 0 ) {
288                                 for ( i = 0; i > di; i-- ) {
289                                         this._$list.children().first().detach();
290                                         idx = this._itemsPerView - parseInt( ( sx / this._itemWidth ) + i, 10 );
291                                         $item = this._items[ circularNum( idx, this._items.length ) ];
292                                         this._$list.append( $item );
293                                         //console.log( "di < 0 : " + idx );
294                                 }
295                         }
296
297                         this._sx += di * this._itemWidth;
298
299                         setElementTransform( this._$view, ( x - this._sx - this._itemWidth ) + "px", 0 );
300
301                         //console.log( "rx " + this._rx + "sx " + this._sx );
302                 },
303
304                 _enableTracking: function () {
305                         $(document).bind( this._dragMoveEvt, this._dragMoveCB );
306                         $(document).bind( this._dragStopEvt, this._dragStopCB );
307                 },
308
309                 _disableTracking: function () {
310                         $(document).unbind( this._dragMoveEvt, this._dragMoveCB );
311                         $(document).unbind( this._dragStopEvt, this._dragStopCB );
312                 },
313
314                 _getScrollHierarchy: function () {
315                         var svh = [],
316                                 d;
317                         this._$clip.parents( '.ui-scrollview-clip' ).each( function () {
318                                 d = $( this ).jqmData( 'circulaview' );
319                                 if ( d ) {
320                                         svh.unshift( d );
321                                 }
322                         } );
323                         return svh;
324                 },
325
326                 centerTo: function ( selector, duration ) {
327                         var i,
328                                 newX;
329
330                         for ( i = 0; i < this._items.length; i++ ) {
331                                 if ( $( this._items[i]).is( selector ) ) {
332                                         newX = -( i * this._itemWidth - this._clipWidth / 2 + this._itemWidth * 1.5 );
333                                         this.scrollTo( newX + this._itemWidth, 0 );
334                                         this.scrollTo( newX, 0, duration );
335                                         return;
336                                 }
337                         }
338                 },
339
340                 scrollTo: function ( x, y, duration ) {
341                         this._stopMScroll();
342                         if ( !duration ) {
343                                 this._setScrollPosition( x, y );
344                                 this._rx = x;
345                                 return;
346                         }
347
348                         var self = this,
349                                 start = getCurrentTime(),
350                                 efunc = $.easing.easeOutQuad,
351                                 sx = this._rx,
352                                 sy = 0,
353                                 dx = x - sx,
354                                 dy = 0,
355                                 tfunc,
356                                 elapsed,
357                                 ec;
358
359                         this._rx = x;
360
361                         tfunc = function () {
362                                 elapsed = getCurrentTime() - start;
363                                 if ( elapsed >= duration ) {
364                                         self._timerID = 0;
365                                         self._setScrollPosition( x, y );
366                                         self._$clip.trigger("scrollend");
367                                 } else {
368                                         ec = efunc( elapsed / duration, elapsed, 0, 1, duration );
369                                         self._setScrollPosition( sx + ( dx * ec ), sy + ( dy * ec ) );
370                                         self._timerID = setTimeout( tfunc, self._timerInterval );
371                                 }
372                         };
373
374                         this._timerID = setTimeout( tfunc, this._timerInterval );
375                 },
376
377                 getScrollPosition: function () {
378                         return { x: -this._rx, y: 0 };
379                 },
380
381                 _handleDragStart: function ( e, ex, ey ) {
382                         $.each( this._getScrollHierarchy(), function ( i, sv ) {
383                                 sv._stopMScroll();
384                         } );
385
386                         this._stopMScroll();
387
388                         if ( this.options.delayedClickEnabled ) {
389                                 this._$clickEle = $( e.target ).closest( this.options.delayedClickSelector );
390                         }
391                         this._lastX = ex;
392                         this._lastY = ey;
393                         this._speedX = 0;
394                         this._speedY = 0;
395                         this._didDrag = false;
396
397                         this._lastMove = 0;
398                         this._enableTracking();
399
400                         this._ox = ex;
401                         this._nx = this._rx;
402
403                         if ( this.options.eventType == "mouse" || this.options.delayedClickEnabled ) {
404                                 e.preventDefault();
405                         }
406                         //console.log( "scrollstart" + this._rx + "," + this._sx );
407                         e.stopPropagation();
408                 },
409
410                 _handleDragMove: function ( e, ex, ey ) {
411                         this._lastMove = getCurrentTime();
412
413                         var dx = ex - this._lastX,
414                                 dy = ey - this._lastY;
415
416                         this._speedX = dx;
417                         this._speedY = 0;
418
419                         this._didDrag = true;
420
421                         this._lastX = ex;
422                         this._lastY = ey;
423
424                         this._mx = ex - this._ox;
425
426                         this._setScrollPosition( this._nx + this._mx, 0 );
427
428                         //console.log( "scrollmove" + this._rx + "," + this._sx );
429                         return false;
430                 },
431
432                 _handleDragStop: function ( e ) {
433                         var l = this._lastMove,
434                                 t = getCurrentTime(),
435                                 doScroll = l && ( t - l ) <= this.options.moveIntervalThreshold,
436                                 sx = ( this._tracker && this._speedX && doScroll ) ? this._speedX : 0,
437                                 sy = 0;
438
439                         this._rx = this._mx ? this._nx + this._mx : this._rx;
440
441                         if ( sx ) {
442                                 this._startMScroll( sx, sy );
443                         }
444
445                         //console.log( "scrollstop" + this._rx + "," + this._sx );
446
447                         this._disableTracking();
448
449                         if ( !this._didDrag && this.options.delayedClickEnabled && this._$clickEle.length ) {
450                                 this._$clickEle
451                                         .trigger( "mousedown" )
452                                         .trigger( "mouseup" )
453                                         .trigger( "click" );
454                         }
455
456                         if ( this._didDrag ) {
457                                 e.preventDefault();
458                                 e.stopPropagation();
459                         }
460
461                         return this._didDrag ? false : undefined;
462                 },
463
464                 _addBehaviors: function () {
465                         var self = this;
466
467                         if ( this.options.eventType === "mouse" ) {
468                                 this._dragStartEvt = "mousedown";
469                                 this._dragStartCB = function ( e ) {
470                                         return self._handleDragStart( e, e.clientX, e.clientY );
471                                 };
472
473                                 this._dragMoveEvt = "mousemove";
474                                 this._dragMoveCB = function ( e ) {
475                                         return self._handleDragMove( e, e.clientX, e.clientY );
476                                 };
477
478                                 this._dragStopEvt = "mouseup";
479                                 this._dragStopCB = function ( e ) {
480                                         return self._handleDragStop( e );
481                                 };
482
483                                 this._$view.bind( "vclick", function (e) {
484                                         return !self._didDrag;
485                                 } );
486
487                         } else { //touch
488                                 this._dragStartEvt = "touchstart";
489                                 this._dragStartCB = function ( e ) {
490                                         var t = e.originalEvent.targetTouches[0];
491                                         return self._handleDragStart(e, t.pageX, t.pageY );
492                                 };
493
494                                 this._dragMoveEvt = "touchmove";
495                                 this._dragMoveCB = function ( e ) {
496                                         var t = e.originalEvent.targetTouches[0];
497                                         return self._handleDragMove(e, t.pageX, t.pageY );
498                                 };
499
500                                 this._dragStopEvt = "touchend";
501                                 this._dragStopCB = function ( e ) {
502                                         return self._handleDragStop( e );
503                                 };
504                         }
505                         this._$view.bind( this._dragStartEvt, this._dragStartCB );
506                 }
507         } );
508
509         $( document ).bind( "pagecreate create", function ( e ) {
510                 $( $.mobile.circularview.prototype.options.initSelector, e.target ).circularview();
511         } );
512
513 }( jQuery, window, document ) ); // End Component
514