Export 0.1.63
[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  *  remove(index): remove the image (parameter: index of image)
39  *  refresh(index): refresh the widget, should be called after add or remove. (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('remove');
64  * });
65  *
66  */
67
68  /**
69         @class ImageSlider
70         The image slider widget shows images in a gallery on the screen. <br/><br/> To add an image slider widget to the application, use the following code:
71
72                 <div data-role="imageslider" id="imageslider" data-vertical-align="middle" data-index="3">
73                         <img src="01.jpg">
74                         <img src="02.jpg">
75                         <img src="03.jpg">
76                         <img src="04.jpg">
77                         <img src="05.jpg">
78                 </div>
79 */
80 /**
81         @property {Integer} data-index
82         Defines the index number of the first image in the gallery.
83         <br/>The default value is 0.
84 */
85 /**
86         @property {String} data-vertical-align
87         Defines the image alignment. The alignment options are top, middle, and bottom.
88         <br/>The default value is top.
89 */
90 /**
91         @method add
92         The add method is used to add an image to the image slider. The image_file attribute defines the image file URL.
93
94                 <div id="imageslider" data-role="imageslider" data-vertical-align="middle"></div>
95                 $("#imageslider").imageslider('add', [image_file]);
96 */
97 /**
98         @method del
99         The del method is used to delete an image from the image slider. The image_index attribute defines the index of the image to be deleted.
100
101                 <div id="imageslider" data-role="imageslider" data-vertical-align="middle"></div>
102                 $("#imageslider").imageslider('del', [image_index]);
103 */
104 /**
105         @method refresh
106         The refresh method is used to refresh the image slider. This method must be called after adding images to the image slider.
107
108                 <div id="imageslider" data-role="imageslider" data-vertical-align="middle"></div>
109                 $("#imageslider").imageslider('refresh');
110 */
111 (function ( $, window, undefined ) {
112         $.widget( "tizen.imageslider", $.mobile.widget, {
113                 options: {
114                         flicking: false,
115                         duration: 500
116                 },
117
118                 dragging: false,
119                 moving: false,
120                 max_width: 0,
121                 max_height: 0,
122                 org_x: 0,
123                 org_time: null,
124                 cur_img: null,
125                 prev_img: null,
126                 next_img: null,
127                 images: [],
128                 images_hold: [],
129                 index: 0,
130                 align_type: null,
131                 direction: 1,
132                 container: null,
133                 loader: [],
134
135                 _resize: function ( index ) {
136                         var img = this.images[index],
137                                 width = this.images[index].width(),
138                                 height = this.images[index].height(),
139                                 margin = 0,
140                                 ratio,
141                                 img_max_width = this.max_width - margin,
142                                 img_max_height = this.max_height - margin;
143
144                         ratio = height / width;
145
146                         if ( width > img_max_width ) {
147                                 img.width( img_max_width );
148                                 img.height( img_max_width * ratio );
149                         }
150
151                         height = img.height();
152
153                         if ( height > img_max_height ) {
154                                 img.height( img_max_height );
155                                 img.width( img_max_height / ratio );
156                         }
157                 },
158
159                 _align: function ( index, obj ) {
160                         var img = this.images[index],
161                                 img_top = 0;
162
163                         if ( !obj) {
164                                 return;
165                         }
166                         if ( !obj.length ) {
167                                 return;
168                         }
169
170                         if ( this.align_type == "middle" ) {
171                                 img_top = ( this.max_height - img.height() ) / 2;
172                         } else if ( this.align_type == "bottom" ) {
173                                 img_top = this.max_height - img.height();
174                         } else {
175                                 img_top = 0;
176                         }
177
178                         obj.css( 'top', img_top + 'px' );
179                 },
180
181                 _attach: function ( index, obj ) {
182                         var self = this,
183                                 processing = function () {
184                                         self._resize( index );
185                                         self._align( index, obj );
186                                 };
187
188                         if ( !obj) {
189                                 return;
190                         }
191                         if ( !obj.length ) {
192                                 return;
193                         }
194                         if ( index < 0 ) {
195                                 return;
196                         }
197                         if ( index >= this.images.length ) {
198                                 return;
199                         }
200
201                         obj.css( "display", "block" );
202                         obj.append( this.images[index] );
203
204                         if ( this.images[index].height() ) {
205                                 processing();
206                         } else {
207                                 this.loader[index] = setInterval( function () {
208                                         if ( !self.images[index].height() ) {
209                                                 return;
210                                         }
211
212                                         processing();
213                                         clearInterval( self.loader[index] );
214                                 }, 10);
215                         }
216                 },
217
218                 _detach: function ( index, obj ) {
219                         if ( !obj) {
220                                 return;
221                         }
222                         if ( !obj.length ) {
223                                 return;
224                         }
225                         if ( index < 0 ) {
226                                 return;
227                         }
228                         if ( index >= this.images.length ) {
229                                 return;
230                         }
231
232                         obj.css( "display", "none" );
233                         this.images[index].removeAttr("style");
234                         this.images[index].detach();
235
236                         clearInterval( this.loader[index] );
237                 },
238
239                 _drag: function ( _x ) {
240                         var delta,
241                                 coord_x;
242
243                         if ( !this.dragging ) {
244                                 return;
245                         }
246
247                         if ( this.options.flicking === false ) {
248                                 delta = this.org_x - _x;
249
250                                 // first image
251                                 if ( delta < 0 && !this.prev_img.length ) {
252                                         return;
253                                 }
254                                 // last image
255                                 if ( delta > 0 && !this.next_img.length ) {
256                                         return;
257                                 }
258                         }
259
260                         coord_x = _x - this.org_x;
261
262                         this.cur_img.css( 'left', coord_x + 'px' );
263                         if ( this.next_img.length ) {
264                                 this.next_img.css( 'left', coord_x + this.window_width + 'px' );
265                         }
266                         if ( this.prev_img.length ) {
267                                 this.prev_img.css( 'left', coord_x - this.window_width + 'px' );
268                         }
269                 },
270
271                 _move: function ( _x ) {
272                         var delta = this.org_x - _x,
273                                 flip = 0,
274                                 drag_time,
275                                 sec,
276                                 self;
277
278                         if ( delta == 0 ) {
279                                 return;
280                         }
281
282                         if ( delta > 0 ) {
283                                 flip = delta < ( this.max_width * 0.45 ) ? 0 : 1;
284                         } else {
285                                 flip = -delta < ( this.max_width * 0.45 ) ? 0 : 1;
286                         }
287
288                         if ( !flip ) {
289                                 drag_time = Date.now() - this.org_time;
290
291                                 if ( Math.abs( delta ) / drag_time > 1 ) {
292                                         flip = 1;
293                                 }
294                         }
295
296                         if ( flip ) {
297                                 if ( delta > 0 && this.next_img.length ) {
298                                         /* next */
299                                         this._detach( this.index - 1, this.prev_img );
300
301                                         this.prev_img = this.cur_img;
302                                         this.cur_img = this.next_img;
303                                         this.next_img = this.next_img.next();
304
305                                         this.index++;
306
307                                         if ( this.next_img.length ) {
308                                                 this.next_img.css( 'left', this.window_width + 'px' );
309                                                 this._attach( this.index + 1, this.next_img );
310                                         }
311
312                                         this.direction = 1;
313
314                                 } else if ( delta < 0 && this.prev_img.length ) {
315                                         /* prev */
316                                         this._detach( this.index + 1, this.next_img );
317
318                                         this.next_img = this.cur_img;
319                                         this.cur_img = this.prev_img;
320                                         this.prev_img = this.prev_img.prev();
321
322                                         this.index--;
323
324                                         if ( this.prev_img.length ) {
325                                                 this.prev_img.css( 'left', -this.window_width + 'px' );
326                                                 this._attach( this.index - 1, this.prev_img );
327                                         }
328
329                                         this.direction = -1;
330                                 }
331                         }
332
333                         sec = this.options.duration;
334                         self = this;
335
336                         this.moving = true;
337
338                         setTimeout( function () {
339                                 self.moving = false;
340                         }, sec - 50 );
341
342                         this.cur_img.animate( { left: 0 }, sec );
343                         if ( this.next_img.length ) {
344                                 this.next_img.animate( { left: this.window_width }, sec );
345                         }
346                         if ( this.prev_img.length ) {
347                                 this.prev_img.animate( { left: -this.window_width }, sec );
348                         }
349                 },
350
351                 _add_event: function () {
352                         var self = this,
353                                 date;
354
355                         this.container.bind( 'vmousemove', function ( e ) {
356                                 e.preventDefault();
357
358                                 if ( self.moving ) {
359                                         return;
360                                 }
361                                 if ( !self.dragging ) {
362                                         return;
363                                 }
364
365                                 self._drag( e.pageX );
366                         } );
367
368                         this.container.bind( 'vmousedown', function ( e ) {
369                                 e.preventDefault();
370
371                                 if ( self.moving ) {
372                                         return;
373                                 }
374
375                                 self.dragging = true;
376
377                                 self.org_x = e.pageX;
378
379                                 self.org_time = Date.now();
380                         } );
381
382                         this.container.bind( 'vmouseup', function ( e ) {
383                                 if ( self.moving ) {
384                                         return;
385                                 }
386
387                                 self.dragging = false;
388
389                                 self._move( e.pageX );
390                         } );
391
392                         this.container.bind( 'vmouseout', function ( e ) {
393                                 if ( self.moving ) {
394                                         return;
395                                 }
396                                 if ( !self.dragging ) {
397                                         return;
398                                 }
399
400                                 if ( ( e.pageX < 20 ) ||
401                                                 ( e.pageX > ( self.max_width - 20 ) ) ) {
402                                         self._move( e.pageX );
403                                         self.dragging = false;
404                                 }
405                         } );
406                 },
407
408                 _del_event: function () {
409                         this.container.unbind( 'vmousemove' );
410                         this.container.unbind( 'vmousedown' );
411                         this.container.unbind( 'vmouseup' );
412                         this.container.unbind( 'vmouseout' );
413                 },
414
415                 _show: function () {
416                         /* resizing */
417                         this.window_width = $( window ).width();
418                         this.max_width = this._get_width();
419                         this.max_height = this._get_height();
420                         this.container.css( 'height', this.max_height );
421
422                         this.cur_img = $( 'div' ).find( '.ui-imageslider-bg:eq(' + this.index + ')' );
423                         this.prev_img = this.cur_img.prev();
424                         this.next_img = this.cur_img.next();
425
426                         this._attach( this.index - 1, this.prev_img );
427                         this._attach( this.index, this.cur_img );
428                         this._attach( this.index + 1, this.next_img );
429
430                         if ( this.prev_img.length ) {
431                                 this.prev_img.css( 'left', -this.window_width + 'px' );
432                         }
433
434                         this.cur_img.css( 'left', '0px' );
435
436                         if ( this.next_img.length ) {
437                                 this.next_img.css( 'left', this.window_width + 'px' );
438                         }
439                 },
440
441                 show: function () {
442                         this._show();
443                         this._add_event();
444                 },
445
446                 _hide: function () {
447                         this._detach( this.index - 1, this.prev_img );
448                         this._detach( this.index, this.cur_img );
449                         this._detach( this.index + 1, this.next_img );
450                 },
451
452                 hide: function () {
453                         this._hide();
454                         this._del_event();
455                 },
456
457                 _get_width: function () {
458                         var $page = $( this.element ).parentsUntil( 'ui-page' ),
459                                 $content = $page.children( '.ui-content' ),
460                                 padding = parseFloat( $content.css( 'padding-left' ) )
461                                         + parseFloat( $content.css( 'padding-right' ) ),
462                                 content_w = $( window ).width() - padding;
463
464                         return content_w;
465                 },
466
467                 _get_height: function () {
468                         var $page = $( this.element ).parentsUntil( 'ui-page' ),
469                                 $content = $page.children( '.ui-content' ),
470                                 header_h = $page.children( '.ui-header' ).outerHeight() || 0,
471                                 footer_h = $page.children( '.ui-footer' ).outerHeight() || 0,
472                                 padding = parseFloat( $content.css( 'padding-top' ) )
473                                         + parseFloat( $content.css( 'padding-bottom' ) ),
474                                 content_h = $( window ).height() - header_h - footer_h - padding;
475
476                         return content_h;
477                 },
478
479                 _create: function () {
480                         var temp_img,
481                                 self = this,
482                                 index,
483                                 i = 0;
484
485                         $( this.element ).wrapInner( '<div class="ui-imageslider"></div>' );
486                         $( this.element ).find( 'img' ).wrap( '<div class="ui-imageslider-bg"></div>' );
487
488                         this.container = $( this.element ).find('.ui-imageslider');
489
490                         temp_img = $( 'div' ).find( '.ui-imageslider-bg:first' );
491
492                         while ( temp_img.length ) {
493                                 this.images[i] = temp_img.find( 'img' );
494                                 temp_img = temp_img.next();
495                                 i++;
496                         }
497
498                         for ( i = 0; i < this.images.length; i++ ) {
499                                 this.images[i].detach();
500                         }
501
502                         index = parseInt( $( this.element ).jqmData( 'index' ), 10 );
503                         if ( !index ) {
504                                 index = 0;
505                         }
506                         if ( index < 0 ) {
507                                 index = 0;
508                         }
509                         if ( index >= this.images.length ) {
510                                 index = this.images.length - 1;
511                         }
512
513                         this.index = index;
514
515                         this.align_type = $( this.element ).jqmData( 'vertical-align' );
516
517                         $( window ).bind( 'resize', function () {
518                                 self.refresh();
519                         });
520                 },
521
522                 _update: function () {
523                         var image_file,
524                                 bg_html,
525                                 temp_img;
526
527                         while ( this.images_hold.length ) {
528                                 image_file = this.images_hold.shift();
529
530                                 bg_html = $( '<div class="ui-imageslider-bg"></div>' );
531                                 temp_img = $( '<img src="' + image_file + '"></div>' );
532
533                                 bg_html.append( temp_img );
534                                 this.container.append( bg_html );
535                                 this.images.push( temp_img );
536                         }
537                 },
538
539                 refresh: function ( start_index ) {
540                         this._update();
541
542                         this._hide();
543
544                         if ( start_index === undefined ) {
545                                 start_index = this.index;
546                         }
547                         if ( start_index < 0 ) {
548                                 start_index = 0;
549                         }
550                         if ( start_index >= this.images.length ) {
551                                 start_index = this.images.length - 1;
552                         }
553
554                         this.index = start_index;
555
556                         this._show();
557                 },
558
559                 add: function ( file ) {
560                         this.images_hold.push( file );
561                 },
562
563                 remove: function ( index ) {
564                         var temp_img;
565
566                         if ( index === undefined ) {
567                                 index = this.index;
568                         }
569
570                         if ( index < 0 || index >= this.images.length ) {
571                                 return;
572                         }
573
574                         if ( index == this.index ) {
575                                 temp_img = this.cur_img;
576
577                                 if ( this.index == 0 ) {
578                                         this.direction = 1;
579                                 } else if ( this.index == this.images.length - 1 ) {
580                                         this.direction = -1;
581                                 }
582
583                                 if ( this.direction < 0 ) {
584                                         this.cur_img = this.prev_img;
585                                         this.prev_img = this.prev_img.prev();
586                                         if ( this.prev_img.length ) {
587                                                 this.prev_img.css( 'left', -this.window_width );
588                                                 this._attach( index - 2, this.prev_img );
589                                         }
590                                         this.index--;
591                                 } else {
592                                         this.cur_img = this.next_img;
593                                         this.next_img = this.next_img.next();
594                                         if ( this.next_img.length ) {
595                                                 this.next_img.css( 'left', this.window_width );
596                                                 this._attach( index + 2, this.next_img );
597                                         }
598                                 }
599
600                                 this.cur_img.animate( { left: 0 }, this.options.duration );
601
602                         } else if ( index == this.index - 1 ) {
603                                 temp_img = this.prev_img;
604                                 this.prev_img = this.prev_img.prev();
605                                 if ( this.prev_img.length ) {
606                                         this.prev_img.css( 'left', -this.window_width );
607                                         this._attach( index - 1, this.prev_img );
608                                 }
609                                 this.index--;
610
611                         } else if ( index == this.index + 1 ) {
612                                 temp_img = this.next_img;
613                                 this.next_img = this.next_img.next();
614                                 if ( this.next_img.length ) {
615                                         this.next_img.css( 'left', this.window_width );
616                                         this._attach( index + 1, this.next_img );
617                                 }
618
619                         } else {
620                                 temp_img = $( 'div' ).find( '.ui-imageslider-bg:eq(' + index + ')' );
621                         }
622
623                         this.images.splice( index, 1 );
624                         temp_img.detach();
625                 }
626         }); /* End of widget */
627
628         // auto self-init widgets
629         $( document ).bind( "pagecreate", function ( e ) {
630                 $( e.target ).find( ":jqmData(role='imageslider')" ).imageslider();
631         });
632
633         $( document ).bind( "pageshow", function ( e ) {
634                 $( e.target ).find( ":jqmData(role='imageslider')" ).imageslider( 'show' );
635         });
636
637         $( document ).bind( "pagebeforehide", function ( e ) {
638                 $( e.target ).find( ":jqmData(role='imageslider')" ).imageslider( 'hide' );
639         } );
640
641 }( jQuery, this ) );