Export 0.1.44
[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.length ) {
121                                 return;
122                         }
123
124                         if ( this.align_type == "middle" ) {
125                                 img_top = ( this.max_height - img.height() ) / 2;
126                         } else if ( this.align_type == "bottom" ) {
127                                 img_top = this.max_height - img.height();
128                         } else {
129                                 img_top = 0;
130                         }
131
132                         obj.css( 'top', img_top + 'px' );
133                 },
134
135                 _attach: function ( index, obj ) {
136                         var self = this,
137                                 processing = function () {
138                                         self._resize( index );
139                                         self._align( index, obj );
140                                 };
141
142                         if ( !obj.length ) {
143                                 return;
144                         }
145                         if ( index < 0 ) {
146                                 return;
147                         }
148                         if ( index >= this.images.length ) {
149                                 return;
150                         }
151
152                         obj.css( "display", "block" );
153                         obj.append( this.images[index] );
154
155                         if ( this.images[index].height() ) {
156                                 processing();
157                         } else {
158                                 this.loader[index] = setInterval( function () {
159                                         if ( !self.images[index].height() ) {
160                                                 return;
161                                         }
162
163                                         processing();
164                                         clearInterval( self.loader[index] );
165                                 }, 10);
166                         }
167                 },
168
169                 _detach: function ( index, obj ) {
170                         if ( !obj.length ) {
171                                 return;
172                         }
173                         if ( index < 0 ) {
174                                 return;
175                         }
176                         if ( index >= this.images.length ) {
177                                 return;
178                         }
179
180                         obj.css( "display", "none" );
181                         this.images[index].removeAttr("style");
182                         this.images[index].detach();
183
184                         clearInterval( this.loader[index] );
185                 },
186
187                 _drag: function ( _x ) {
188                         var delta,
189                                 coord_x;
190
191                         if ( !this.dragging ) {
192                                 return;
193                         }
194
195                         if ( this.options.flicking === false ) {
196                                 delta = this.org_x - _x;
197
198                                 // first image
199                                 if ( delta < 0 && !this.prev_img.length ) {
200                                         return;
201                                 }
202                                 // last image
203                                 if ( delta > 0 && !this.next_img.length ) {
204                                         return;
205                                 }
206                         }
207
208                         coord_x = _x - this.org_x;
209
210                         this.cur_img.css( 'left', coord_x + 'px' );
211                         if ( this.next_img.length ) {
212                                 this.next_img.css( 'left', coord_x + this.window_width + 'px' );
213                         }
214                         if ( this.prev_img.length ) {
215                                 this.prev_img.css( 'left', coord_x - this.window_width + 'px' );
216                         }
217                 },
218
219                 _move: function ( _x ) {
220                         var delta = this.org_x - _x,
221                                 flip = 0,
222                                 date,
223                                 drag_time,
224                                 sec,
225                                 self;
226
227                         if ( delta == 0 ) {
228                                 return;
229                         }
230
231                         if ( delta > 0 ) {
232                                 flip = delta < ( this.max_width * 0.45 ) ? 0 : 1;
233                         } else {
234                                 flip = -delta < ( this.max_width * 0.45 ) ? 0 : 1;
235                         }
236
237                         if ( !flip ) {
238                                 date = new Date();
239                                 drag_time = date.getTime() - this.org_time;
240
241                                 if ( Math.abs( delta ) / drag_time > 1 ) {
242                                         flip = 1;
243                                 }
244                         }
245
246                         if ( flip ) {
247                                 if ( delta > 0 && this.next_img.length ) {
248                                         /* next */
249                                         this._detach( this.index - 1, this.prev_img );
250
251                                         this.prev_img = this.cur_img;
252                                         this.cur_img = this.next_img;
253                                         this.next_img = this.next_img.next();
254
255                                         this.index++;
256
257                                         if ( this.next_img.length ) {
258                                                 this.next_img.css( 'left', this.window_width + 'px' );
259                                                 this._attach( this.index + 1, this.next_img );
260                                         }
261
262                                         this.direction = 1;
263
264                                 } else if ( delta < 0 && this.prev_img.length ) {
265                                         /* prev */
266                                         this._detach( this.index + 1, this.next_img );
267
268                                         this.next_img = this.cur_img;
269                                         this.cur_img = this.prev_img;
270                                         this.prev_img = this.prev_img.prev();
271
272                                         this.index--;
273
274                                         if ( this.prev_img.length ) {
275                                                 this.prev_img.css( 'left', -this.window_width + 'px' );
276                                                 this._attach( this.index - 1, this.prev_img );
277                                         }
278
279                                         this.direction = -1;
280                                 }
281                         }
282
283                         sec = this.options.duration;
284                         self = this;
285
286                         this.moving = true;
287
288                         setTimeout( function () {
289                                 self.moving = false;
290                         }, sec - 50 );
291
292                         this.cur_img.animate( { left: 0 }, sec );
293                         if ( this.next_img.length ) {
294                                 this.next_img.animate( { left: this.window_width }, sec );
295                         }
296                         if ( this.prev_img.length ) {
297                                 this.prev_img.animate( { left: -this.window_width }, sec );
298                         }
299                 },
300
301                 _add_event: function () {
302                         var self = this,
303                                 date;
304
305                         this.container.bind( 'vmousemove', function ( e ) {
306                                 e.preventDefault();
307
308                                 if ( self.moving ) {
309                                         return;
310                                 }
311                                 if ( !self.dragging ) {
312                                         return;
313                                 }
314
315                                 self._drag( e.pageX );
316                         } );
317
318                         this.container.bind( 'vmousedown', function ( e ) {
319                                 e.preventDefault();
320
321                                 if ( self.moving ) {
322                                         return;
323                                 }
324
325                                 self.dragging = true;
326
327                                 self.org_x = e.pageX;
328
329                                 date = new Date();
330                                 self.org_time = date.getTime();
331                         } );
332
333                         this.container.bind( 'vmouseup', function ( e ) {
334                                 if ( self.moving ) {
335                                         return;
336                                 }
337
338                                 self.dragging = false;
339
340                                 self._move( e.pageX );
341                         } );
342
343                         this.container.bind( 'vmouseout', function ( e ) {
344                                 if ( self.moving ) {
345                                         return;
346                                 }
347                                 if ( !self.dragging ) {
348                                         return;
349                                 }
350
351                                 if ( ( e.pageX < 20 ) ||
352                                                 ( e.pageX > ( self.max_width - 20 ) ) ) {
353                                         self._move( e.pageX );
354                                         self.dragging = false;
355                                 }
356                         } );
357                 },
358
359                 _del_event: function () {
360                         this.container.unbind( 'vmousemove' );
361                         this.container.unbind( 'vmousedown' );
362                         this.container.unbind( 'vmouseup' );
363                         this.container.unbind( 'vmouseout' );
364                 },
365
366                 _show: function () {
367                         /* resizing */
368                         this.window_width = $( window ).width();
369                         this.max_width = this._get_width();
370                         this.max_height = this._get_height();
371                         this.container.css( 'height', this.max_height );
372
373                         this.cur_img = $( 'div' ).find( '.ui-imageslider-bg:eq(' + this.index + ')' );
374                         this.prev_img = this.cur_img.prev();
375                         this.next_img = this.cur_img.next();
376
377                         this._attach( this.index - 1, this.prev_img );
378                         this._attach( this.index, this.cur_img );
379                         this._attach( this.index + 1, this.next_img );
380
381                         if ( this.prev_img.length ) {
382                                 this.prev_img.css( 'left', -this.window_width + 'px' );
383                         }
384
385                         this.cur_img.css( 'left', '0px' );
386
387                         if ( this.next_img.length ) {
388                                 this.next_img.css( 'left', this.window_width + 'px' );
389                         }
390                 },
391
392                 show: function () {
393                         this._show();
394                         this._add_event();
395                 },
396
397                 _hide: function () {
398                         this._detach( this.index - 1, this.prev_img );
399                         this._detach( this.index, this.cur_img );
400                         this._detach( this.index + 1, this.next_img );
401                 },
402
403                 hide: function () {
404                         this._hide();
405                         this._del_event();
406                 },
407
408                 _get_width: function () {
409                         var $page = $( this.element ).parentsUntil( 'ui-page' ),
410                                 $content = $page.children( '.ui-content' ),
411                                 padding = parseFloat( $content.css( 'padding-left' ) )
412                                         + parseFloat( $content.css( 'padding-right' ) ),
413                                 content_w = $( window ).width() - padding;
414
415                         return content_w;
416                 },
417
418                 _get_height: function () {
419                         var $page = $( this.element ).parentsUntil( 'ui-page' ),
420                                 $content = $page.children( '.ui-content' ),
421                                 header_h = $page.children( '.ui-header' ).outerHeight() || 0,
422                                 footer_h = $page.children( '.ui-footer' ).outerHeight() || 0,
423                                 padding = parseFloat( $content.css( 'padding-top' ) )
424                                         + parseFloat( $content.css( 'padding-bottom' ) ),
425                                 content_h = $( window ).height() - header_h - footer_h - padding;
426
427                         return content_h;
428                 },
429
430                 _create: function () {
431                         var temp_img,
432                                 self = this,
433                                 index,
434                                 i = 0;
435
436                         $( this.element ).wrapInner( '<div class="ui-imageslider"></div>' );
437                         $( this.element ).find( 'img' ).wrap( '<div class="ui-imageslider-bg"></div>' );
438
439                         this.container = $( this.element ).find('.ui-imageslider');
440
441                         temp_img = $( 'div' ).find( '.ui-imageslider-bg:first' );
442
443                         while ( temp_img.length ) {
444                                 this.images[i] = temp_img.find( 'img' );
445                                 temp_img = temp_img.next();
446                                 i++;
447                         }
448
449                         for ( i = 0; i < this.images.length; i++ ) {
450                                 this.images[i].detach();
451                         }
452
453                         index = parseInt( $( this.element ).jqmData( 'index' ), 10 );
454                         if ( !index ) {
455                                 index = 0;
456                         }
457                         if ( index < 0 ) {
458                                 index = 0;
459                         }
460                         if ( index >= this.images.length ) {
461                                 index = this.images.length - 1;
462                         }
463
464                         this.index = index;
465
466                         this.align_type = $( this.element ).jqmData( 'vertical-align' );
467
468                         $( window ).bind( 'resize', function () {
469                                 self.refresh();
470                         });
471                 },
472
473                 _update: function () {
474                         var image_file,
475                                 bg_html,
476                                 temp_img;
477
478                         while ( this.images_hold.length ) {
479                                 image_file = this.images_hold.shift();
480
481                                 bg_html = $( '<div class="ui-imageslider-bg"></div>' );
482                                 temp_img = $( '<img src="' + image_file + '"></div>' );
483
484                                 bg_html.append( temp_img );
485                                 this.container.append( bg_html );
486                                 this.images.push( temp_img );
487                         }
488                 },
489
490                 refresh: function ( start_index ) {
491                         this._update();
492
493                         this._hide();
494
495                         if ( start_index === undefined ) {
496                                 start_index = this.index;
497                         }
498                         if ( start_index < 0 ) {
499                                 start_index = 0;
500                         }
501                         if ( start_index >= this.images.length ) {
502                                 start_index = this.images.length - 1;
503                         }
504
505                         this.index = start_index;
506
507                         this._show();
508                 },
509
510                 add: function ( file ) {
511                         this.images_hold.push( file );
512                 },
513
514                 delete: function ( index ) {
515                         var temp_img;
516
517                         if ( index === undefined ) {
518                                 index = this.index;
519                         }
520
521                         if ( index < 0 || index >= this.images.length ) {
522                                 return;
523                         }
524
525                         if ( index == this.index ) {
526                                 temp_img = this.cur_img;
527
528                                 if ( this.index == 0 ) {
529                                         this.direction = 1;
530                                 } else if ( this.index == this.images.length - 1 ) {
531                                         this.direction = -1;
532                                 }
533
534                                 if ( this.direction < 0 ) {
535                                         this.cur_img = this.prev_img;
536                                         this.prev_img = this.prev_img.prev();
537                                         if ( this.prev_img.length ) {
538                                                 this.prev_img.css( 'left', -this.window_width );
539                                                 this._attach( index - 2, this.prev_img );
540                                         }
541                                         this.index--;
542                                 } else {
543                                         this.cur_img = this.next_img;
544                                         this.next_img = this.next_img.next();
545                                         if ( this.next_img.length ) {
546                                                 this.next_img.css( 'left', this.window_width );
547                                                 this._attach( index + 2, this.next_img );
548                                         }
549                                 }
550
551                                 this.cur_img.animate( { left: 0 }, this.options.duration );
552
553                         } else if ( index == this.index - 1 ) {
554                                 temp_img = this.prev_img;
555                                 this.prev_img = this.prev_img.prev();
556                                 if ( this.prev_img.length ) {
557                                         this.prev_img.css( 'left', -this.window_width );
558                                         this._attach( index - 1, this.prev_img );
559                                 }
560                                 this.index--;
561
562                         } else if ( index == this.index + 1 ) {
563                                 temp_img = this.next_img;
564                                 this.next_img = this.next_img.next();
565                                 if ( this.next_img.length ) {
566                                         this.next_img.css( 'left', this.window_width );
567                                         this._attach( index + 1, this.next_img );
568                                 }
569
570                         } else {
571                                 temp_img = $( 'div' ).find( '.ui-imageslider-bg:eq(' + index + ')' );
572                         }
573
574                         this.images.splice( index, 1 );
575                         temp_img.detach();
576                 }
577         }); /* End of widget */
578
579         // auto self-init widgets
580         $( document ).bind( "pagecreate", function ( e ) {
581                 $( e.target ).find( ":jqmData(role='imageslider')" ).imageslider();
582         });
583
584         $( document ).bind( "pageshow", function ( e ) {
585                 $( e.target ).find( ":jqmData(role='imageslider')" ).imageslider( 'show' );
586         });
587
588         $( document ).bind( "pagebeforehide", function ( e ) {
589                 $( e.target ).find( ":jqmData(role='imageslider')" ).imageslider( 'hide' );
590         } );
591
592 }( jQuery, this ) );