c03fceed81cf458ecea99fcfa87244f0f883a02b
[platform/framework/web/web-ui-fw.git] / src / js / widgets / jquery.mobile.tizen.gallery.js
1 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
2 //>>description: Shows images one by one, and moves them by flicking
3 //>>label: Gallery
4 //>>group: Tizen:Widgets
5
6 define( [ ], function ( ) {
7 //>>excludeEnd("jqmBuildExclude");
8
9 /* ***************************************************************************
10  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a
13  * copy of this software and associated documentation files (the "Software"),
14  * to deal in the Software without restriction, including without limitation
15  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16  * and/or sell copies of the Software, and to permit persons to whom the
17  * Software is furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included in
20  * all copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28  * DEALINGS IN THE SOFTWARE.
29  * ***************************************************************************
30  *
31  *      Author: Minkyu Kang <mk7.kang@samsung.com>
32  */
33
34 /*
35  * Gallery widget
36  *
37  * HTML Attributes
38  *
39  *  data-role: set to 'gallery'
40  *  data-index: start index
41  *  data-vertical-align: set to top or middle or bottom.
42  *
43  * APIs
44  *
45  *  add(file): add the image (parameter: url of iamge)
46  *  remove(index): remove the image (parameter: index of image)
47  *  refresh(index): refresh the widget, should be called after add or remove. (parameter: start index)
48  *  empty: remove all of images from the gallery
49  *  length: get length of images
50  *  value(index): get or set current index of gallery (parameter: index of image)
51  *
52  * Events
53  *
54  *  N/A
55  *
56  * Example
57  *
58  * <div data-role="gallery" id="gallery" data-index="3" data-vertical-align="middle">
59  *      <img src="01.jpg">
60  *      <img src="02.jpg">
61  *      <img src="03.jpg">
62  *      <img src="04.jpg">
63  *      <img src="05.jpg">
64  * </div>
65  *
66  *
67  * $('#gallery-add').bind('vmouseup', function ( e ) {
68  *      $('#gallery').gallery('add', '9.jpg');
69  *      $('#gallery').gallery('add', '10.jpg');
70  *      $('#gallery').gallery('refresh');
71  * });
72  *
73  * $('#gallery-del').bind('vmouseup', function ( e ) {
74  *      $('#gallery').gallery('remove');
75  * });
76  *
77  */
78
79  /**
80         @class Gallery
81         The gallery widget shows images in a gallery on the screen. <br/><br/> To add an gallery widget to the application, use the following code:
82
83                 <div data-role="gallery" id="gallery" data-vertical-align="middle" data-index="3">
84                         <img src="01.jpg">
85                         <img src="02.jpg">
86                         <img src="03.jpg">
87                         <img src="04.jpg">
88                         <img src="05.jpg">
89                 </div>
90 */
91 /**
92         @property {Integer} data-index
93         Defines the index number of the first image in the gallery.
94         <br/>The default value is 0.
95 */
96 /**
97         @property {String} data-vertical-align
98         Defines the image alignment. The alignment options are top, middle, and bottom.
99         <br/>The default value is top.
100 */
101 /**
102         @method add
103         The add method is used to add an image to the gallery. The image_file attribute defines the image file URL.
104
105                 <div id="gallery" data-role="gallery" data-vertical-align="middle"></div>
106                 $("#gallery").gallery('add', [image_file]);
107 */
108 /**
109         @method remove
110         The remove method is used to delete an image from the gallery. The image_index attribute defines the index of the image to be deleted. If not set removes current image.
111
112                 <div id="gallery" data-role="gallery" data-vertical-align="middle"></div>
113                 $("#gallery").gallery('remove', [image_index]);
114 */
115 /**
116         @method refresh
117         The refresh method is used to refresh the gallery. This method must be called after adding images to the gallery.
118
119                 <div id="gallery" data-role="gallery" data-vertical-align="middle"></div>
120                 $("#gallery").gallery('refresh');
121 */
122 /**
123         @method empty
124         The empty method is used to remove all of images from the gallery.
125
126                 <div id="gallery" data-role="gallery" data-vertical-align="middle"></div>
127                 $("#gallery").gallery('empty');
128 */
129 /**
130         @method length
131         The length method is used to get length of images.
132
133                 <div id="gallery" data-role="gallery" data-vertical-align="middle"></div>
134                 length = $("#gallery").gallery('length');
135 */
136 /**
137         @method value
138         The value method is used to get or set current index of gallery. The image_index attribute defines the index of the image to be set. If not get current index.
139
140                 <div id="gallery" data-role="gallery" data-vertical-align="middle"></div>
141                 value = $("#gallery").gallery('value');
142                 $("#gallery").gallery('value', [image_index]);
143 */
144 (function ( $, window, undefined ) {
145         $.widget( "tizen.gallery", $.mobile.widget, {
146                 options: {
147                         flicking: false,
148                         duration: 500
149                 },
150
151                 dragging: false,
152                 moving: false,
153                 max_width: 0,
154                 max_height: 0,
155                 org_x: 0,
156                 org_time: null,
157                 cur_img: null,
158                 prev_img: null,
159                 next_img: null,
160                 images: [],
161                 images_hold: [],
162                 index: 0,
163                 align_type: null,
164                 direction: 1,
165                 container: null,
166                 orientationEventFire: false,
167
168                 _resize: function ( index ) {
169                         var img = this.images[index],
170                                 width = this.images[index].width(),
171                                 height = this.images[index].height(),
172                                 margin = 0,
173                                 ratio,
174                                 img_max_width = this.max_width - margin,
175                                 img_max_height = this.max_height - margin;
176
177                         ratio = height / width;
178
179                         if ( width > img_max_width ) {
180                                 img.width( img_max_width );
181                                 img.height( img_max_width * ratio );
182                         }
183
184                         height = img.height();
185
186                         if ( height > img_max_height ) {
187                                 img.height( img_max_height );
188                                 img.width( img_max_height / ratio );
189                         }
190                 },
191
192                 _align: function ( index, obj ) {
193                         var img = this.images[index],
194                                 img_top = 0;
195
196                         if ( !obj ) {
197                                 return;
198                         }
199                         if ( !obj.length ) {
200                                 return;
201                         }
202
203                         if ( this.align_type == "middle" ) {
204                                 img_top = ( this.max_height - img.height() ) / 2;
205                         } else if ( this.align_type == "bottom" ) {
206                                 img_top = this.max_height - img.height();
207                         } else {
208                                 img_top = 0;
209                         }
210
211                         obj.css( 'top', img_top + 'px' );
212                 },
213
214                 _attach: function ( index, obj ) {
215                         var self = this,
216                                 processing = function () {
217                                         self._resize( index );
218                                         self._align( index, obj );
219                                 },
220                                 loading = function () {
221                                         if ( self.images[index] === undefined ) {
222                                                 return;
223                                         }
224
225                                         if ( !self.images[index].height() ) {
226                                                 setTimeout( loading, 10 );
227                                                 return;
228                                         }
229
230                                         processing();
231                                 };
232
233                         if ( !obj ) {
234                                 return;
235                         }
236                         if ( !obj.length ) {
237                                 return;
238                         }
239                         if ( index < 0 ) {
240                                 return;
241                         }
242                         if ( !this.images.length ) {
243                                 return;
244                         }
245                         if ( index >= this.images.length ) {
246                                 return;
247                         }
248
249                         obj.css( "display", "block" );
250                         obj.append( this.images[index] );
251                         loading();
252                 },
253
254                 _detach: function ( index, obj ) {
255                         if ( !obj ) {
256                                 return;
257                         }
258                         if ( !obj.length ) {
259                                 return;
260                         }
261                         if ( index < 0 ) {
262                                 return;
263                         }
264                         if ( index >= this.images.length ) {
265                                 return;
266                         }
267
268                         obj.css( "display", "none" );
269                         this.images[index].removeAttr("style");
270                         this.images[index].detach();
271                 },
272
273                 _detach_all: function () {
274                         var i;
275
276                         for ( i = 0; i < this.images.length; i++ ) {
277                                 this.images[i].detach();
278                         }
279                 },
280
281                 _drag: function ( _x ) {
282                         var delta,
283                                 coord_x;
284
285                         if ( !this.dragging ) {
286                                 return;
287                         }
288
289                         if ( this.options.flicking === false ) {
290                                 delta = this.org_x - _x;
291
292                                 // first image
293                                 if ( delta < 0 && !this.prev_img.length ) {
294                                         return;
295                                 }
296                                 // last image
297                                 if ( delta > 0 && !this.next_img.length ) {
298                                         return;
299                                 }
300                         }
301
302                         coord_x = _x - this.org_x;
303
304                         this._moveLeft( this.cur_img , coord_x + 'px');
305                         if ( this.next_img.length ) {
306                                 this._moveLeft( this.next_img ,  coord_x + this.window_width + 'px' );
307                         }
308                         if ( this.prev_img.length ) {
309                                 this._moveLeft( this.prev_img ,  coord_x - this.window_width + 'px' );
310                         }
311                 },
312
313                 _move: function ( _x ) {
314                         var delta = this.org_x - _x,
315                                 flip = 0,
316                                 drag_time,
317                                 sec,
318                                 self;
319
320                         if ( delta == 0 ) {
321                                 return;
322                         }
323
324                         if ( delta > 0 ) {
325                                 flip = delta < ( this.max_width * 0.45 ) ? 0 : 1;
326                         } else {
327                                 flip = -delta < ( this.max_width * 0.45 ) ? 0 : 1;
328                         }
329
330                         if ( !flip ) {
331                                 drag_time = Date.now() - this.org_time;
332
333                                 if ( Math.abs( delta ) / drag_time > 1 ) {
334                                         flip = 1;
335                                 }
336                         }
337
338                         if ( flip ) {
339                                 if ( delta > 0 && this.next_img.length ) {
340                                         /* next */
341                                         this._detach( this.index - 1, this.prev_img );
342
343                                         this.prev_img = this.cur_img;
344                                         this.cur_img = this.next_img;
345                                         this.next_img = this.next_img.next();
346
347                                         this.index++;
348
349                                         if ( this.next_img.length ) {
350                                                 this._moveLeft( this.next_img ,  this.window_width + 'px' );
351                                                 this._attach( this.index + 1, this.next_img );
352                                         }
353
354                                         this.direction = 1;
355
356                                 } else if ( delta < 0 && this.prev_img.length ) {
357                                         /* prev */
358                                         this._detach( this.index + 1, this.next_img );
359
360                                         this.next_img = this.cur_img;
361                                         this.cur_img = this.prev_img;
362                                         this.prev_img = this.prev_img.prev();
363
364                                         this.index--;
365
366                                         if ( this.prev_img.length ) {
367                                                 this._moveLeft( this.prev_img , -this.window_width + 'px' );
368                                                 this._attach( this.index - 1, this.prev_img );
369                                         }
370
371                                         this.direction = -1;
372                                 }
373                         }
374
375                         sec = this.options.duration;
376                         self = this;
377
378                         this.moving = true;
379
380                         setTimeout( function () {
381                                 self.moving = false;
382                         }, sec - 25 );
383
384                         this._moveLeft( this.cur_img, 0 + 'px', sec );
385                         if ( this.next_img.length ) {
386                                 this._moveLeft( this.next_img, this.window_width + 'px', sec );
387                         }
388                         if ( this.prev_img.length ) {
389                                 this._moveLeft( this.prev_img, -this.window_width + 'px', sec );
390                         }
391                 },
392
393                 _add_event: function () {
394                         var self = this,
395                                 date;
396
397                         this.container.bind( 'vmousemove', function ( e ) {
398                                 e.preventDefault();
399
400                                 if ( self.moving ) {
401                                         return;
402                                 }
403                                 if ( !self.dragging ) {
404                                         return;
405                                 }
406
407                                 self._drag( e.pageX );
408                         } );
409
410                         this.container.bind( 'vmousedown', function ( e ) {
411                                 e.preventDefault();
412
413                                 if ( self.moving ) {
414                                         return;
415                                 }
416
417                                 self.dragging = true;
418
419                                 self.org_x = e.pageX;
420
421                                 self.org_time = Date.now();
422                         } );
423
424                         this.container.bind( 'vmouseup', function ( e ) {
425                                 if ( self.moving ) {
426                                         return;
427                                 }
428
429                                 self.dragging = false;
430
431                                 self._move( e.pageX );
432                         } );
433
434                         this.container.bind( 'vmouseout', function ( e ) {
435                                 if ( self.moving ) {
436                                         return;
437                                 }
438                                 if ( !self.dragging ) {
439                                         return;
440                                 }
441
442                                 if ( ( e.pageX < 20 ) ||
443                                                 ( e.pageX > ( self.max_width - 20 ) ) ) {
444                                         self._move( e.pageX );
445                                         self.dragging = false;
446                                 }
447                         } );
448                 },
449
450                 _del_event: function () {
451                         this.container.unbind( 'vmousemove' );
452                         this.container.unbind( 'vmousedown' );
453                         this.container.unbind( 'vmouseup' );
454                         this.container.unbind( 'vmouseout' );
455                 },
456                 _setTranslateposition : function ( $ele, value ) {
457                         var translate,
458                                 cssArray = null;
459
460                         if ( $.support.cssTransform3d ) {
461                                 translate = "translate3d(" + value + ", 0px, 0px)";
462                         } else {
463                                 translate = "translate(" + value + ", 0px)";
464                         }
465                         cssArray = {"-moz-transform": translate,
466                                         "-webkit-transform": translate,
467                                         "-ms-transform": translate,
468                                         "-o-transform": translate,
469                                         "transform": translate};
470
471                         $ele.css(cssArray);
472                         return $ele;
473                 },
474                 _moveLeft : function ( $ele , value , duration) {
475                         var translate,
476                                 transition = "",
477                                 cssArray = null;
478
479                         if ( $.support.cssTransform3d ) {
480                                 translate = "translate3d(" + value + ", 0px, 0px)";
481                         } else {
482                                 translate = "translate(" + value + ", 0px)";
483                         }
484                         if( duration !== undefined ) {
485                                 transition =  "-webkit-transform " + (duration / 1000)+ "s ease";
486                         }
487                         cssArray = {"-moz-transform": translate,
488                                         "-webkit-transform": translate,
489                                         "-ms-transform": translate,
490                                         "-o-transform": translate,
491                                         "transform": translate};
492                         if( transition !== "" ) {
493                                 cssArray["-webkit-transition"] = transition ;
494                         }
495
496                         $ele.css(cssArray);
497                         return $ele;
498                 },
499                 _show: function () {
500                         /* resizing */
501                         this.window_width = $( window ).width();
502                         this.max_width = this._get_width();
503                         this.max_height = this._get_height();
504                         this.container.css( 'height', this.max_height );
505
506                         this.cur_img = $( 'div' ).find( '.ui-gallery-bg:eq(' + this.index + ')' );
507                         this.prev_img = this.cur_img.prev();
508                         this.next_img = this.cur_img.next();
509
510                         this._attach( this.index - 1, this.prev_img );
511                         this._attach( this.index, this.cur_img );
512                         this._attach( this.index + 1, this.next_img );
513
514                         if ( this.prev_img.length ) {
515                                 this._setTranslateposition( this.prev_img, -this.window_width + 'px');
516                         }
517
518                         this._moveLeft( this.cur_img, '0px');
519                         if ( this.next_img.length ) {
520                                 this._setTranslateposition( this.next_img, this.window_width + 'px' );
521                         }
522                 },
523
524                 show: function () {
525                         if ( !this.images.length ) {
526                                 return;
527                         }
528
529                         this._show();
530                         this._add_event();
531                 },
532
533                 _hide: function () {
534                         this._detach( this.index - 1, this.prev_img );
535                         this._detach( this.index, this.cur_img );
536                         this._detach( this.index + 1, this.next_img );
537                 },
538
539                 hide: function () {
540                         this._hide();
541                         this._del_event();
542                 },
543
544                 _get_width: function () {
545                         return $( this.element ).width();
546                 },
547
548                 _get_height: function () {
549                         var $page = $( this.element ).parentsUntil( 'ui-page' ),
550                                 $content = $page.children( '.ui-content' ),
551                                 header_h = $page.children( '.ui-header' ).outerHeight() || 0,
552                                 footer_h = $page.children( '.ui-footer' ).outerHeight() || 0,
553                                 padding = parseFloat( $content.css( 'padding-top' ) )
554                                         + parseFloat( $content.css( 'padding-bottom' ) ),
555                                 content_h = $( window ).height() - header_h - footer_h - padding;
556
557                         return content_h;
558                 },
559
560                 _create: function () {
561                         var temp_img,
562                                 self = this,
563                                 index,
564                                 i = 0;
565
566                         $( this.element ).wrapInner( '<div class="ui-gallery"></div>' );
567                         $( this.element ).find( 'img' ).wrap( '<div class="ui-gallery-bg"></div>' );
568
569                         this.container = $( this.element ).find('.ui-gallery');
570
571                         temp_img = $( 'div' ).find( '.ui-gallery-bg:first' );
572
573                         while ( temp_img.length ) {
574                                 this.images[i] = temp_img.find( 'img' );
575                                 temp_img = temp_img.next();
576                                 i++;
577                         }
578
579                         this._detach_all();
580
581                         index = parseInt( $( this.element ).jqmData( 'index' ), 10 );
582                         if ( !index ) {
583                                 index = 0;
584                         }
585                         if ( index < 0 ) {
586                                 index = 0;
587                         }
588                         if ( index >= this.images.length ) {
589                                 index = this.images.length - 1;
590                         }
591
592                         this.index = index;
593
594                         this.align_type = $( this.element ).jqmData( 'vertical-align' );
595
596                         $.extend( this, {
597                                 _globalHandlers: [
598                                         {
599                                                 src: $( window ),
600                                                 handler: {
601                                                         orientationchange: $.proxy( this, "_orientationHandler" ),
602                                                         resize: $.proxy( this, "_resizeHandler" )
603                                                 }
604                                         }
605                                 ]
606                         });
607
608                         $.each( this._globalHandlers, function( idx, value ) {
609                                 value.src.bind( value.handler );
610                         });
611                 },
612
613                 _update: function () {
614                         var image_file,
615                                 bg_html,
616                                 temp_img;
617
618                         while ( this.images_hold.length ) {
619                                 image_file = this.images_hold.shift();
620
621                                 bg_html = $( '<div class="ui-gallery-bg"></div>' );
622                                 temp_img = $( '<img src="' + image_file + '"></div>' );
623
624                                 bg_html.append( temp_img );
625                                 this.container.append( bg_html );
626                                 this.images.push( temp_img );
627                         }
628
629                         this._detach_all();
630                 },
631                 _resizeHandler: function() {
632                         var self = this;
633                         if( self.orientationEventFire ) {
634                                 self.refresh();
635                                 self.orientationEventFire = false;
636                         }
637                 },
638                 _orientationHandler: function() {
639                         var self = this;
640                         self.refresh();
641                         self.orientationEventFire = true;
642                 },
643                 refresh: function ( start_index ) {
644                         this._update();
645
646                         this._hide();
647
648                         if ( start_index === undefined ) {
649                                 start_index = this.index;
650                         }
651                         if ( start_index < 0 ) {
652                                 start_index = 0;
653                         }
654                         if ( start_index >= this.images.length ) {
655                                 start_index = this.images.length - 1;
656                         }
657
658                         this.index = start_index;
659
660                         this._show();
661
662                         return this.index;
663                 },
664
665                 add: function ( file ) {
666                         this.images_hold.push( file );
667                 },
668
669                 remove: function ( index ) {
670                         var temp_img;
671
672                         if ( index === undefined ) {
673                                 index = this.index;
674                         }
675
676                         if ( index < 0 || index >= this.images.length ) {
677                                 return;
678                         }
679
680                         if ( index == this.index ) {
681                                 temp_img = this.cur_img;
682
683                                 if ( this.index == 0 ) {
684                                         this.direction = 1;
685                                 } else if ( this.index == this.images.length - 1 ) {
686                                         this.direction = -1;
687                                 }
688
689                                 if ( this.direction < 0 ) {
690                                         this.cur_img = this.prev_img;
691                                         this.prev_img = this.prev_img.prev();
692                                         if ( this.prev_img.length ) {
693                                                 this._moveLeft( this.prev_img, -this.window_width + 'px' );
694                                                 this._attach( index - 2, this.prev_img );
695                                         }
696                                         this.index--;
697                                 } else {
698                                         this.cur_img = this.next_img;
699                                         this.next_img = this.next_img.next();
700                                         if ( this.next_img.length ) {
701                                                 this._moveLeft( this.next_img, this.window_width + 'px' );
702                                                 this._attach( index + 2, this.next_img );
703                                         }
704                                 }
705                                 this._moveLeft( this.cur_img, '0px', this.options.duration );
706
707                         } else if ( index == this.index - 1 ) {
708                                 temp_img = this.prev_img;
709                                 this.prev_img = this.prev_img.prev();
710                                 if ( this.prev_img.length ) {
711                                         this._moveLeft( this.prev_img, -this.window_width + 'px' );
712                                         this._attach( index - 1, this.prev_img );
713                                 }
714                                 this.index--;
715
716                         } else if ( index == this.index + 1 ) {
717                                 temp_img = this.next_img;
718                                 this.next_img = this.next_img.next();
719                                 if ( this.next_img.length ) {
720                                         this._moveLeft( this.next_img, this.window_width + 'px' );
721                                         this._attach( index + 1, this.next_img );
722                                 }
723
724                         } else {
725                                 temp_img = $( 'div' ).find( '.ui-gallery-bg:eq(' + index + ')' );
726                         }
727
728                         this.images.splice( index, 1 );
729                         temp_img.detach();
730                 },
731
732                 empty: function () {
733                         this.images.splice( 0, this.images.length );
734                         this.container.find('.ui-gallery-bg').detach();
735                 },
736
737                 length: function () {
738                         return this.images.length;
739                 },
740
741                 value: function ( index ) {
742                         if ( index === undefined ) {
743                                 return this.index;
744                         }
745
746                         this.refresh( index );
747                 },
748
749                 destory: function() {
750                         $( window ).unbind( 'resize', this._resizeHandler );
751                         $( window ).unbind( 'orientationchange' , this._orientationHandler );
752                 }
753
754         }); /* End of widget */
755
756         // auto self-init widgets
757         $( document ).bind( "pagecreate create", function ( e ) {
758                 $( e.target ).find( ":jqmData(role='gallery')" ).gallery();
759         });
760
761         $( document ).bind( "pageshow", function ( e ) {
762                 $( e.target ).find( ":jqmData(role='gallery')" ).gallery( 'show' );
763         });
764
765         $( document ).bind( "pagebeforehide", function ( e ) {
766                 $( e.target ).find( ":jqmData(role='gallery')" ).gallery( 'hide' );
767         } );
768
769 }( jQuery, this ) );
770
771 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
772 } );
773 //>>excludeEnd("jqmBuildExclude");