fc42b02456025c3b8c171ff9ae721ceb193d6a59
[platform/framework/web/web-ui-fw.git] / src / widgets / imageslider / js / jquery.mobile.tizen.imageslider.js
1 /* ***************************************************************************
2  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  * ***************************************************************************
22  *
23  *      Author: Minkyu Kang <mk7.kang@samsung.com>
24  */
25
26 /*
27  * Imageslider widget
28  *
29  * HTML Attributes
30  *
31  *  data-role: set to 'imageslider'
32  *  data-index: start index
33  *  data-vertical-align: set to top or middle or bottom.
34  *
35  * APIs
36  *
37  *  add(file): add the image (parameter: url of iamge)
38  *  delete(index): delete the image (parameter: index of image)
39  *  refresh(index): refresh the widget, should be called after add or del. (parameter: start index)
40  *
41  * Events
42  *
43  *  N/A
44  *
45  * Example
46  *
47  * <div data-role="imageslider" id="imageslider" data-index="3" data-vertical-align="middle">
48  *      <img src="01.jpg">
49  *      <img src="02.jpg">
50  *      <img src="03.jpg">
51  *      <img src="04.jpg">
52  *      <img src="05.jpg">
53  * </div>
54  *
55  *
56  * $('#imageslider-add').bind('vmouseup', function ( e ) {
57  *      $('#imageslider').imageslider('add', '9.jpg');
58  *      $('#imageslider').imageslider('add', '10.jpg');
59  *      $('#imageslider').imageslider('refresh');
60  * });
61  *
62  * $('#imageslider-del').bind('vmouseup', function ( e ) {
63  *      $('#imageslider').imageslider('delete');
64  * });
65  *
66  */
67
68 (function ( $, window, undefined ) {
69         $.widget( "tizen.imageslider", $.mobile.widget, {
70                 options: {
71                         flicking: false,
72                         duration: 500
73                 },
74
75                 dragging: false,
76                 moving: false,
77                 max_width: 0,
78                 max_height: 0,
79                 org_x: 0,
80                 org_time: null,
81                 cur_img: null,
82                 prev_img: null,
83                 next_img: null,
84                 images: [],
85                 images_hold: [],
86                 index: 0,
87                 align_type: null,
88                 direction: 1,
89                 container: null,
90                 loader: [],
91
92                 _resize: function ( index ) {
93                         var img = this.images[index],
94                                 width = this.images[index].width(),
95                                 height = this.images[index].height(),
96                                 margin = 0,
97                                 ratio,
98                                 img_max_width = this.max_width - margin,
99                                 img_max_height = this.max_height - margin;
100
101                         ratio = height / width;
102
103                         if ( width > img_max_width ) {
104                                 img.width( img_max_width );
105                                 img.height( img_max_width * ratio );
106                         }
107
108                         height = img.height();
109
110                         if ( height > img_max_height ) {
111                                 img.height( img_max_height );
112                                 img.width( img_max_height / ratio );
113                         }
114                 },
115
116                 _align: function ( index, obj ) {
117                         var img = this.images[index],
118                                 img_top = 0;
119
120                         if ( !obj) {
121                                 return;
122                         }
123                         if ( !obj.length ) {
124                                 return;
125                         }
126
127                         if ( this.align_type == "middle" ) {
128                                 img_top = ( this.max_height - img.height() ) / 2;
129                         } else if ( this.align_type == "bottom" ) {
130                                 img_top = this.max_height - img.height();
131                         } else {
132                                 img_top = 0;
133                         }
134
135                         obj.css( 'top', img_top + 'px' );
136                 },
137
138                 _attach: function ( index, obj ) {
139                         var self = this,
140                                 processing = function () {
141                                         self._resize( index );
142                                         self._align( index, obj );
143                                 };
144
145                         if ( !obj) {
146                                 return;
147                         }
148                         if ( !obj.length ) {
149                                 return;
150                         }
151                         if ( index < 0 ) {
152                                 return;
153                         }
154                         if ( index >= this.images.length ) {
155                                 return;
156                         }
157
158                         obj.css( "display", "block" );
159                         obj.append( this.images[index] );
160
161                         if ( this.images[index].height() ) {
162                                 processing();
163                         } else {
164                                 this.loader[index] = setInterval( function () {
165                                         if ( !self.images[index].height() ) {
166                                                 return;
167                                         }
168
169                                         processing();
170                                         clearInterval( self.loader[index] );
171                                 }, 10);
172                         }
173                 },
174
175                 _detach: function ( index, obj ) {
176                         if ( !obj) {
177                                 return;
178                         }
179                         if ( !obj.length ) {
180                                 return;
181                         }
182                         if ( index < 0 ) {
183                                 return;
184                         }
185                         if ( index >= this.images.length ) {
186                                 return;
187                         }
188
189                         obj.css( "display", "none" );
190                         this.images[index].removeAttr("style");
191                         this.images[index].detach();
192
193                         clearInterval( this.loader[index] );
194                 },
195
196                 _drag: function ( _x ) {
197                         var delta,
198                                 coord_x;
199
200                         if ( !this.dragging ) {
201                                 return;
202                         }
203
204                         if ( this.options.flicking === false ) {
205                                 delta = this.org_x - _x;
206
207                                 // first image
208                                 if ( delta < 0 && !this.prev_img.length ) {
209                                         return;
210                                 }
211                                 // last image
212                                 if ( delta > 0 && !this.next_img.length ) {
213                                         return;
214                                 }
215                         }
216
217                         coord_x = _x - this.org_x;
218
219                         this.cur_img.css( 'left', coord_x + 'px' );
220                         if ( this.next_img.length ) {
221                                 this.next_img.css( 'left', coord_x + this.window_width + 'px' );
222                         }
223                         if ( this.prev_img.length ) {
224                                 this.prev_img.css( 'left', coord_x - this.window_width + 'px' );
225                         }
226                 },
227
228                 _move: function ( _x ) {
229                         var delta = this.org_x - _x,
230                                 flip = 0,
231                                 drag_time,
232                                 sec,
233                                 self;
234
235                         if ( delta == 0 ) {
236                                 return;
237                         }
238
239                         if ( delta > 0 ) {
240                                 flip = delta < ( this.max_width * 0.45 ) ? 0 : 1;
241                         } else {
242                                 flip = -delta < ( this.max_width * 0.45 ) ? 0 : 1;
243                         }
244
245                         if ( !flip ) {
246                                 drag_time = Date.now() - this.org_time;
247
248                                 if ( Math.abs( delta ) / drag_time > 1 ) {
249                                         flip = 1;
250                                 }
251                         }
252
253                         if ( flip ) {
254                                 if ( delta > 0 && this.next_img.length ) {
255                                         /* next */
256                                         this._detach( this.index - 1, this.prev_img );
257
258                                         this.prev_img = this.cur_img;
259                                         this.cur_img = this.next_img;
260                                         this.next_img = this.next_img.next();
261
262                                         this.index++;
263
264                                         if ( this.next_img.length ) {
265                                                 this.next_img.css( 'left', this.window_width + 'px' );
266                                                 this._attach( this.index + 1, this.next_img );
267                                         }
268
269                                         this.direction = 1;
270
271                                 } else if ( delta < 0 && this.prev_img.length ) {
272                                         /* prev */
273                                         this._detach( this.index + 1, this.next_img );
274
275                                         this.next_img = this.cur_img;
276                                         this.cur_img = this.prev_img;
277                                         this.prev_img = this.prev_img.prev();
278
279                                         this.index--;
280
281                                         if ( this.prev_img.length ) {
282                                                 this.prev_img.css( 'left', -this.window_width + 'px' );
283                                                 this._attach( this.index - 1, this.prev_img );
284                                         }
285
286                                         this.direction = -1;
287                                 }
288                         }
289
290                         sec = this.options.duration;
291                         self = this;
292
293                         this.moving = true;
294
295                         setTimeout( function () {
296                                 self.moving = false;
297                         }, sec - 50 );
298
299                         this.cur_img.animate( { left: 0 }, sec );
300                         if ( this.next_img.length ) {
301                                 this.next_img.animate( { left: this.window_width }, sec );
302                         }
303                         if ( this.prev_img.length ) {
304                                 this.prev_img.animate( { left: -this.window_width }, sec );
305                         }
306                 },
307
308                 _add_event: function () {
309                         var self = this,
310                                 date;
311
312                         this.container.bind( 'vmousemove', function ( e ) {
313                                 e.preventDefault();
314
315                                 if ( self.moving ) {
316                                         return;
317                                 }
318                                 if ( !self.dragging ) {
319                                         return;
320                                 }
321
322                                 self._drag( e.pageX );
323                         } );
324
325                         this.container.bind( 'vmousedown', function ( e ) {
326                                 e.preventDefault();
327
328                                 if ( self.moving ) {
329                                         return;
330                                 }
331
332                                 self.dragging = true;
333
334                                 self.org_x = e.pageX;
335
336                                 self.org_time = Date.now();
337                         } );
338
339                         this.container.bind( 'vmouseup', function ( e ) {
340                                 if ( self.moving ) {
341                                         return;
342                                 }
343
344                                 self.dragging = false;
345
346                                 self._move( e.pageX );
347                         } );
348
349                         this.container.bind( 'vmouseout', function ( e ) {
350                                 if ( self.moving ) {
351                                         return;
352                                 }
353                                 if ( !self.dragging ) {
354                                         return;
355                                 }
356
357                                 if ( ( e.pageX < 20 ) ||
358                                                 ( e.pageX > ( self.max_width - 20 ) ) ) {
359                                         self._move( e.pageX );
360                                         self.dragging = false;
361                                 }
362                         } );
363                 },
364
365                 _del_event: function () {
366                         this.container.unbind( 'vmousemove' );
367                         this.container.unbind( 'vmousedown' );
368                         this.container.unbind( 'vmouseup' );
369                         this.container.unbind( 'vmouseout' );
370                 },
371
372                 _show: function () {
373                         /* resizing */
374                         this.window_width = $( window ).width();
375                         this.max_width = this._get_width();
376                         this.max_height = this._get_height();
377                         this.container.css( 'height', this.max_height );
378
379                         this.cur_img = $( 'div' ).find( '.ui-imageslider-bg:eq(' + this.index + ')' );
380                         this.prev_img = this.cur_img.prev();
381                         this.next_img = this.cur_img.next();
382
383                         this._attach( this.index - 1, this.prev_img );
384                         this._attach( this.index, this.cur_img );
385                         this._attach( this.index + 1, this.next_img );
386
387                         if ( this.prev_img.length ) {
388                                 this.prev_img.css( 'left', -this.window_width + 'px' );
389                         }
390
391                         this.cur_img.css( 'left', '0px' );
392
393                         if ( this.next_img.length ) {
394                                 this.next_img.css( 'left', this.window_width + 'px' );
395                         }
396                 },
397
398                 show: function () {
399                         this._show();
400                         this._add_event();
401                 },
402
403                 _hide: function () {
404                         this._detach( this.index - 1, this.prev_img );
405                         this._detach( this.index, this.cur_img );
406                         this._detach( this.index + 1, this.next_img );
407                 },
408
409                 hide: function () {
410                         this._hide();
411                         this._del_event();
412                 },
413
414                 _get_width: function () {
415                         var $page = $( this.element ).parentsUntil( 'ui-page' ),
416                                 $content = $page.children( '.ui-content' ),
417                                 padding = parseFloat( $content.css( 'padding-left' ) )
418                                         + parseFloat( $content.css( 'padding-right' ) ),
419                                 content_w = $( window ).width() - padding;
420
421                         return content_w;
422                 },
423
424                 _get_height: function () {
425                         var $page = $( this.element ).parentsUntil( 'ui-page' ),
426                                 $content = $page.children( '.ui-content' ),
427                                 header_h = $page.children( '.ui-header' ).outerHeight() || 0,
428                                 footer_h = $page.children( '.ui-footer' ).outerHeight() || 0,
429                                 padding = parseFloat( $content.css( 'padding-top' ) )
430                                         + parseFloat( $content.css( 'padding-bottom' ) ),
431                                 content_h = $( window ).height() - header_h - footer_h - padding;
432
433                         return content_h;
434                 },
435
436                 _create: function () {
437                         var temp_img,
438                                 self = this,
439                                 index,
440                                 i = 0;
441
442                         $( this.element ).wrapInner( '<div class="ui-imageslider"></div>' );
443                         $( this.element ).find( 'img' ).wrap( '<div class="ui-imageslider-bg"></div>' );
444
445                         this.container = $( this.element ).find('.ui-imageslider');
446
447                         temp_img = $( 'div' ).find( '.ui-imageslider-bg:first' );
448
449                         while ( temp_img.length ) {
450                                 this.images[i] = temp_img.find( 'img' );
451                                 temp_img = temp_img.next();
452                                 i++;
453                         }
454
455                         for ( i = 0; i < this.images.length; i++ ) {
456                                 this.images[i].detach();
457                         }
458
459                         index = parseInt( $( this.element ).jqmData( 'index' ), 10 );
460                         if ( !index ) {
461                                 index = 0;
462                         }
463                         if ( index < 0 ) {
464                                 index = 0;
465                         }
466                         if ( index >= this.images.length ) {
467                                 index = this.images.length - 1;
468                         }
469
470                         this.index = index;
471
472                         this.align_type = $( this.element ).jqmData( 'vertical-align' );
473
474                         $( window ).bind( 'resize', function () {
475                                 self.refresh();
476                         });
477                 },
478
479                 _update: function () {
480                         var image_file,
481                                 bg_html,
482                                 temp_img;
483
484                         while ( this.images_hold.length ) {
485                                 image_file = this.images_hold.shift();
486
487                                 bg_html = $( '<div class="ui-imageslider-bg"></div>' );
488                                 temp_img = $( '<img src="' + image_file + '"></div>' );
489
490                                 bg_html.append( temp_img );
491                                 this.container.append( bg_html );
492                                 this.images.push( temp_img );
493                         }
494                 },
495
496                 refresh: function ( start_index ) {
497                         this._update();
498
499                         this._hide();
500
501                         if ( start_index === undefined ) {
502                                 start_index = this.index;
503                         }
504                         if ( start_index < 0 ) {
505                                 start_index = 0;
506                         }
507                         if ( start_index >= this.images.length ) {
508                                 start_index = this.images.length - 1;
509                         }
510
511                         this.index = start_index;
512
513                         this._show();
514                 },
515
516                 add: function ( file ) {
517                         this.images_hold.push( file );
518                 },
519
520                 delete: function ( index ) {
521                         var temp_img;
522
523                         if ( index === undefined ) {
524                                 index = this.index;
525                         }
526
527                         if ( index < 0 || index >= this.images.length ) {
528                                 return;
529                         }
530
531                         if ( index == this.index ) {
532                                 temp_img = this.cur_img;
533
534                                 if ( this.index == 0 ) {
535                                         this.direction = 1;
536                                 } else if ( this.index == this.images.length - 1 ) {
537                                         this.direction = -1;
538                                 }
539
540                                 if ( this.direction < 0 ) {
541                                         this.cur_img = this.prev_img;
542                                         this.prev_img = this.prev_img.prev();
543                                         if ( this.prev_img.length ) {
544                                                 this.prev_img.css( 'left', -this.window_width );
545                                                 this._attach( index - 2, this.prev_img );
546                                         }
547                                         this.index--;
548                                 } else {
549                                         this.cur_img = this.next_img;
550                                         this.next_img = this.next_img.next();
551                                         if ( this.next_img.length ) {
552                                                 this.next_img.css( 'left', this.window_width );
553                                                 this._attach( index + 2, this.next_img );
554                                         }
555                                 }
556
557                                 this.cur_img.animate( { left: 0 }, this.options.duration );
558
559                         } else if ( index == this.index - 1 ) {
560                                 temp_img = this.prev_img;
561                                 this.prev_img = this.prev_img.prev();
562                                 if ( this.prev_img.length ) {
563                                         this.prev_img.css( 'left', -this.window_width );
564                                         this._attach( index - 1, this.prev_img );
565                                 }
566                                 this.index--;
567
568                         } else if ( index == this.index + 1 ) {
569                                 temp_img = this.next_img;
570                                 this.next_img = this.next_img.next();
571                                 if ( this.next_img.length ) {
572                                         this.next_img.css( 'left', this.window_width );
573                                         this._attach( index + 1, this.next_img );
574                                 }
575
576                         } else {
577                                 temp_img = $( 'div' ).find( '.ui-imageslider-bg:eq(' + index + ')' );
578                         }
579
580                         this.images.splice( index, 1 );
581                         temp_img.detach();
582                 }
583         }); /* End of widget */
584
585         // auto self-init widgets
586         $( document ).bind( "pagecreate", function ( e ) {
587                 $( e.target ).find( ":jqmData(role='imageslider')" ).imageslider();
588         });
589
590         $( document ).bind( "pageshow", function ( e ) {
591                 $( e.target ).find( ":jqmData(role='imageslider')" ).imageslider( 'show' );
592         });
593
594         $( document ).bind( "pagebeforehide", function ( e ) {
595                 $( e.target ).find( ":jqmData(role='imageslider')" ).imageslider( 'hide' );
596         } );
597
598 }( jQuery, this ) );