You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by pp...@apache.org on 2013/09/10 20:04:15 UTC

[10/51] [partial] [cordova-tizen] Tizen SDK 2.2 support mores samples

http://git-wip-us.apache.org/repos/asf/cordova-tizen/blob/4ebce38e/samples/TizenWebUI-sample-v1/tizen-web-ui-fw/latest/js/modules/widgets/jquery.mobile.tizen.gallery.js
----------------------------------------------------------------------
diff --git a/samples/TizenWebUI-sample-v1/tizen-web-ui-fw/latest/js/modules/widgets/jquery.mobile.tizen.gallery.js b/samples/TizenWebUI-sample-v1/tizen-web-ui-fw/latest/js/modules/widgets/jquery.mobile.tizen.gallery.js
new file mode 100644
index 0000000..08afe90
--- /dev/null
+++ b/samples/TizenWebUI-sample-v1/tizen-web-ui-fw/latest/js/modules/widgets/jquery.mobile.tizen.gallery.js
@@ -0,0 +1,828 @@
+//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
+//>>description: Shows images one by one, and moves them by flicking
+//>>label: Gallery
+//>>group: Tizen:Widgets
+
+define( [ 
+	'jquery',
+	"jqm/jquery.mobile.widget"
+	], function ( jQuery ) {
+
+//>>excludeEnd("jqmBuildExclude");
+
+/* ***************************************************************************
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * ***************************************************************************
+ *
+ *	Author: Minkyu Kang <mk...@samsung.com>
+ */
+
+/*
+ * Gallery widget
+ *
+ * HTML Attributes
+ *
+ *  data-role: set to 'gallery'
+ *  data-index: start index
+ *  data-vertical-align: set to top or middle or bottom.
+ *
+ * APIs
+ *
+ *  add(file): add the image (parameter: url of iamge)
+ *  remove(index): remove the image (parameter: index of image)
+ *  refresh(index): refresh the widget, should be called after add or remove. (parameter: start index)
+ *  empty: remove all of images from the gallery
+ *  length: get length of images
+ *  value(index): get or set current index of gallery (parameter: index of image)
+ *
+ * Events
+ *
+ *  N/A
+ *
+ * Example
+ *
+ * <div data-role="gallery" id="gallery" data-index="3" data-vertical-align="middle">
+ *	<img src="01.jpg">
+ *	<img src="02.jpg">
+ *	<img src="03.jpg">
+ *	<img src="04.jpg">
+ *	<img src="05.jpg">
+ * </div>
+ *
+ *
+ * $('#gallery-add').bind('vmouseup', function ( e ) {
+ *	$('#gallery').gallery('add', '9.jpg');
+ *	$('#gallery').gallery('add', '10.jpg');
+ *	$('#gallery').gallery('refresh');
+ * });
+ *
+ * $('#gallery-del').bind('vmouseup', function ( e ) {
+ *	$('#gallery').gallery('remove');
+ * });
+ *
+ */
+
+ /**
+	@class Gallery
+	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:
+
+		<div data-role="gallery" id="gallery" data-vertical-align="middle" data-index="3">
+			<img src="01.jpg">
+			<img src="02.jpg">
+			<img src="03.jpg">
+			<img src="04.jpg">
+			<img src="05.jpg">
+		</div>
+*/
+/**
+	@property {Integer} data-index
+	Defines the index number of the first image in the gallery.
+	<br/>The default value is 0.
+*/
+/**
+	@property {String} data-vertical-align
+	Defines the image alignment. The alignment options are top, middle, and bottom.
+	<br/>The default value is top.
+*/
+/**
+	@method add
+	The add method is used to add an image to the gallery. The image_file attribute defines the image file URL.
+
+		<div id="gallery" data-role="gallery" data-vertical-align="middle"></div>
+		$("#gallery").gallery('add', [image_file]);
+*/
+/**
+	@method remove
+	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.
+
+		<div id="gallery" data-role="gallery" data-vertical-align="middle"></div>
+		$("#gallery").gallery('remove', [image_index]);
+*/
+/**
+	@method refresh
+	The refresh method is used to refresh the gallery. This method must be called after adding images to the gallery.
+
+		<div id="gallery" data-role="gallery" data-vertical-align="middle"></div>
+		$("#gallery").gallery('refresh');
+*/
+/**
+	@method empty
+	The empty method is used to remove all of images from the gallery.
+
+		<div id="gallery" data-role="gallery" data-vertical-align="middle"></div>
+		$("#gallery").gallery('empty');
+*/
+/**
+	@method length
+	The length method is used to get length of images.
+
+		<div id="gallery" data-role="gallery" data-vertical-align="middle"></div>
+		length = $("#gallery").gallery('length');
+*/
+/**
+	@method value
+	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.
+
+		<div id="gallery" data-role="gallery" data-vertical-align="middle"></div>
+		value = $("#gallery").gallery('value');
+		$("#gallery").gallery('value', [image_index]);
+*/
+(function ( $, window, undefined ) {
+	$.widget( "tizen.gallery", $.mobile.widget, {
+		options: {
+			flicking: false,
+			duration: 500
+		},
+
+		dragging: false,
+		moving: false,
+		max_width: 0,
+		max_height: 0,
+		org_x: 0,
+		org_time: null,
+		cur_img: null,
+		prev_img: null,
+		next_img: null,
+		images: [],
+		images_hold: [],
+		index: 0,
+		align_type: null,
+		direction: 1,
+		container: null,
+		orientationEventFire: false,
+
+		_resize: function ( index ) {
+			var img = this.images[index],
+				width = this.images[index].width(),
+				height = this.images[index].height(),
+				margin = 0,
+				ratio,
+				img_max_width = this.max_width - margin,
+				img_max_height = this.max_height - margin;
+
+			ratio = height / width;
+
+			if( img_max_width == 0 && isNaN( img_max_height ) ) {
+				/*
+				Exception : When image max width and height has incorrect value.
+				This exception is occured when this.max_width value is 0 and this.max_height value is NaN when page transition like rotation.
+				This exception affect that image width and height values are 0.
+				*/
+				img.width( width );
+				img.height( width * ratio );
+			} else {
+				if ( width > img_max_width ) {
+					img.width( img_max_width );
+					img.height( img_max_width * ratio );
+				}
+
+				height = img.height();
+
+				if ( height > img_max_height ) {
+					img.height( img_max_height );
+					img.width( img_max_height / ratio );
+				}
+			}
+		},
+
+		_align: function ( index, obj ) {
+			var img = this.images[index],
+				img_top = 0;
+
+			if ( !obj ) {
+				return;
+			}
+			if ( !obj.length ) {
+				return;
+			}
+
+			if ( this.align_type == "middle" ) {
+				img_top = ( this.max_height - img.height() ) / 2;
+			} else if ( this.align_type == "bottom" ) {
+				img_top = this.max_height - img.height();
+			} else {
+				img_top = 0;
+			}
+
+			obj.css( 'top', img_top + 'px' );
+		},
+
+		_attach: function ( index, obj ) {
+			var self = this,
+				processing = function () {
+					self._resize( index );
+					self._align( index, obj );
+
+				},
+				loading = function () {
+					if ( self.images[index] === undefined ) {
+						return;
+					}
+
+					if ( !self.images[index].height() ) {
+						setTimeout( loading, 10 );
+						return;
+					}
+
+					processing();
+				};
+
+			if ( !obj ) {
+				return;
+			}
+			if ( !obj.length ) {
+				return;
+			}
+			if ( index < 0 ) {
+				return;
+			}
+			if ( !this.images.length ) {
+				return;
+			}
+			if ( index >= this.images.length ) {
+				return;
+			}
+
+			obj.css( "display", "block" );
+			obj.css( "visibility", "hidden" );
+			obj.append( this.images[index] );
+			loading();
+		},
+
+		_detach: function ( index, obj ) {
+			if ( !obj ) {
+				return;
+			}
+			if ( !obj.length ) {
+				return;
+			}
+			if ( index < 0 ) {
+				return;
+			}
+			if ( index >= this.images.length ) {
+				return;
+			}
+
+			obj.css( "display", "none" );
+			this.images[index].removeAttr("style");
+			this.images[index].detach();
+		},
+
+		_detach_all: function () {
+			var i;
+
+			for ( i = 0; i < this.images.length; i++ ) {
+				this.images[i].detach();
+			}
+		},
+
+		_drag: function ( _x ) {
+			var delta,
+				coord_x;
+
+			if ( !this.dragging ) {
+				return;
+			}
+
+			if ( this.options.flicking === false ) {
+				delta = this.org_x - _x;
+
+				// first image
+				if ( delta < 0 && !this.prev_img.length ) {
+					return;
+				}
+				// last image
+				if ( delta > 0 && !this.next_img.length ) {
+					return;
+				}
+			}
+
+			coord_x = _x - this.org_x;
+
+			this._moveLeft( this.cur_img , coord_x + 'px' );
+			if ( this.next_img.length ) {
+				this._moveLeft( this.next_img ,  coord_x + this.window_width + 'px' );
+			}
+			if ( this.prev_img.length ) {
+				this._moveLeft( this.prev_img ,  coord_x - this.window_width + 'px' );
+			}
+		},
+
+		_move: function ( _x ) {
+			var delta = this.org_x - _x,
+				flip = 0,
+				drag_time,
+				sec,
+				self;
+
+			if ( delta == 0 ) {
+				return;
+			}
+
+			if ( delta > 0 ) {
+				flip = delta < ( this.max_width * 0.45 ) ? 0 : 1;
+			} else {
+				flip = -delta < ( this.max_width * 0.45 ) ? 0 : 1;
+			}
+
+			if ( !flip ) {
+				drag_time = Date.now() - this.org_time;
+
+				if ( Math.abs( delta ) / drag_time > 1 ) {
+					flip = 1;
+				}
+			}
+
+			if ( flip ) {
+				if ( delta > 0 && this.next_img.length ) {
+					/* next */
+					this._detach( this.index - 1, this.prev_img );
+
+					this.prev_img = this.cur_img;
+					this.cur_img = this.next_img;
+					this.next_img = this.next_img.next();
+
+					this.index++;
+
+					if ( this.next_img.length ) {
+						this._moveLeft( this.next_img ,  this.window_width + 'px' );
+						this._attach( this.index + 1, this.next_img );
+					}
+
+					this.direction = 1;
+
+				} else if ( delta < 0 && this.prev_img.length ) {
+					/* prev */
+					this._detach( this.index + 1, this.next_img );
+
+					this.next_img = this.cur_img;
+					this.cur_img = this.prev_img;
+					this.prev_img = this.prev_img.prev();
+
+					this.index--;
+
+					if ( this.prev_img.length ) {
+						this._moveLeft( this.prev_img , -this.window_width + 'px' );
+						this._attach( this.index - 1, this.prev_img );
+					}
+
+					this.direction = -1;
+				}
+			}
+
+			sec = this.options.duration;
+			self = this;
+
+			this.moving = true;
+
+			setTimeout( function () {
+				self.moving = false;
+			}, sec - 25 );
+
+			this._moveLeft( this.cur_img, 0 + 'px', sec );
+			if ( this.next_img.length ) {
+				this._moveLeft( this.next_img, this.window_width + 'px', sec );
+			}
+			if ( this.prev_img.length ) {
+				this._moveLeft( this.prev_img, -this.window_width + 'px', sec );
+			}
+		},
+
+		_add_event: function () {
+			var self = this,
+				date;
+
+			this.container.bind( 'vmousemove', function ( e ) {
+				e.preventDefault();
+
+				if ( self.moving ) {
+					return;
+				}
+				if ( !self.dragging ) {
+					return;
+				}
+
+				self._drag( e.pageX );
+			} );
+
+			this.container.bind( 'vmousedown', function ( e ) {
+				e.preventDefault();
+
+				if ( self.moving ) {
+					return;
+				}
+
+				self.dragging = true;
+
+				self.org_x = e.pageX;
+
+				self.org_time = Date.now();
+			} );
+
+			this.container.bind( 'vmouseup', function ( e ) {
+				if ( self.moving ) {
+					return;
+				}
+
+				self.dragging = false;
+
+				self._move( e.pageX );
+			} );
+
+			this.container.bind( 'vmouseout', function ( e ) {
+				if ( self.moving ) {
+					return;
+				}
+				if ( !self.dragging ) {
+					return;
+				}
+
+				if ( ( e.pageX < 20 ) ||
+						( e.pageX > ( self.max_width - 20 ) ) ) {
+					self._move( e.pageX );
+					self.dragging = false;
+				}
+			} );
+		},
+
+		_del_event: function () {
+			this.container.unbind( 'vmousemove' );
+			this.container.unbind( 'vmousedown' );
+			this.container.unbind( 'vmouseup' );
+			this.container.unbind( 'vmouseout' );
+		},
+		_setTranslateposition : function ( $ele, value ) {
+			var translate,
+				cssArray = null,
+				self = this;
+
+			if ( $.support.cssTransform3d ) {
+				translate = "translate3d(" + value + ", 0px, 0px)";
+			} else {
+				translate = "translate(" + value + ", 0px)";
+			}
+			cssArray = {"-moz-transform": translate,
+					"-webkit-transform": translate,
+					"-ms-transform": translate,
+					"-o-transform": translate,
+					"transform": translate};
+
+			$ele.css(cssArray);
+			return $ele;
+		},
+		_hidePrevNext : function() {
+			var self = this;
+
+			if( self.next_img ) {
+				self.next_img.css( "visibility", "hidden" );
+			}
+			if( self.prev_img ) {
+				self.prev_img.css( "visibility", "hidden" );
+			}
+
+		},
+		_hideCur : function() {
+			var self = this;
+			if( self.cur_img ) {
+				self.cur_img.css( "visibility", "hidden" );
+			}
+		},
+		_moveLeft : function ( $ele , value , duration ) {
+			var translate,
+				transition = "",
+				cssArray = null,
+				self = this;
+
+			if ( $.support.cssTransform3d ) {
+				translate = "translate3d(" + value + ", 0px, 0px)";
+			} else {
+				translate = "translate(" + value + ", 0px)";
+			}
+			if( duration !== undefined ) {
+				transition =  "-webkit-transform " + (duration / 1000)+ "s ease";
+			}
+			cssArray = {"-moz-transform": translate,
+					"-webkit-transform": translate,
+					"-ms-transform": translate,
+					"-o-transform": translate,
+					"transform": translate};
+			if( transition !== "" ) {
+				cssArray["-webkit-transition"] = transition ;
+				if( value == "0px" ) {
+					$ele.one( 'webkitTransitionEnd', self._hidePrevNext );
+				} else {
+					$ele.one( 'webkitTransitionEnd', self._hideCur );
+				}
+			}
+			if( value == "0px" ) {
+				$ele.css( "visibility", "visible" );
+			}
+
+			$ele.css(cssArray);
+			return $ele;
+		},
+		_show: function () {
+			/* resizing */
+			this.window_width = $( window ).width();
+			this.max_width = this._get_width();
+			this.max_height = this._get_height();
+			this.container.css( 'height', this.max_height );
+
+			this.cur_img = $( 'div' ).find( '.ui-gallery-bg:eq(' + this.index + ')' );
+			this.prev_img = this.cur_img.prev();
+			this.next_img = this.cur_img.next();
+
+			this._attach( this.index - 1, this.prev_img );
+			this._attach( this.index, this.cur_img );
+			this._attach( this.index + 1, this.next_img );
+
+			this.cur_img.css( 'visibility', 'visible' );
+			if ( this.prev_img.length ) {
+				this._setTranslateposition( this.prev_img, -this.window_width + 'px');
+			}
+
+			this._moveLeft( this.cur_img, '0px');
+			if ( this.next_img.length ) {
+				this._setTranslateposition( this.next_img, this.window_width + 'px' );
+			}
+		},
+
+		show: function () {
+			if ( !this.images.length ) {
+				return;
+			}
+
+			this._show();
+			this._add_event();
+		},
+
+		_hide: function () {
+			this._detach( this.index - 1, this.prev_img );
+			this._detach( this.index, this.cur_img );
+			this._detach( this.index + 1, this.next_img );
+		},
+
+		hide: function () {
+			this._hide();
+			this._del_event();
+		},
+
+		_get_width: function () {
+			return $( this.element ).width();
+		},
+
+		_get_height: function () {
+			var $page = $( this.element ).parentsUntil( 'ui-page' ),
+				$content = $page.children( '.ui-content' ),
+				header_h = $page.children( '.ui-header' ).outerHeight() || 0,
+				footer_h = $page.children( '.ui-footer' ).outerHeight() || 0,
+				padding = parseFloat( $content.css( 'padding-top' ) )
+					+ parseFloat( $content.css( 'padding-bottom' ) ),
+				content_h = $( window ).height() - header_h - footer_h - padding;
+
+			return content_h;
+		},
+
+		_create: function () {
+			var temp_img,
+				self = this,
+				index,
+				i = 0;
+
+			$( this.element ).wrapInner( '<div class="ui-gallery"></div>' );
+			$( this.element ).find( 'img' ).wrap( '<div class="ui-gallery-bg"></div>' );
+
+			this.container = $( this.element ).find('.ui-gallery');
+
+			temp_img = $( 'div' ).find( '.ui-gallery-bg:first' );
+
+			while ( temp_img.length ) {
+				this.images[i] = temp_img.find( 'img' );
+				temp_img = temp_img.next();
+				i++;
+			}
+
+			this._detach_all();
+
+			index = parseInt( $( this.element ).jqmData( 'index' ), 10 );
+			if ( !index ) {
+				index = 0;
+			}
+			if ( index < 0 ) {
+				index = 0;
+			}
+			if ( index >= this.images.length ) {
+				index = this.images.length - 1;
+			}
+
+			this.index = index;
+
+			this.align_type = $( this.element ).jqmData( 'vertical-align' );
+
+			$.extend( this, {
+				_globalHandlers: [
+					{
+						src: $( window ),
+						handler: {
+							orientationchange: $.proxy( this, "_orientationHandler" ),
+							resize: $.proxy( this, "_resizeHandler" )
+						}
+					}
+				]
+			});
+
+			$.each( this._globalHandlers, function( idx, value ) {
+				value.src.bind( value.handler );
+			});
+		},
+
+		_update: function () {
+			var image_file,
+				bg_html,
+				temp_img;
+
+			while ( this.images_hold.length ) {
+				image_file = this.images_hold.shift();
+
+				bg_html = $( '<div class="ui-gallery-bg"></div>' );
+				temp_img = $( '<img src="' + image_file + '"></div>' );
+
+				bg_html.append( temp_img );
+				this.container.append( bg_html );
+				this.images.push( temp_img );
+			}
+
+			this._detach_all();
+		},
+		_resizeHandler: function() {
+			var self = this;
+			if( self.orientationEventFire ) {
+				self.refresh();
+				$( event.target ).trigger( "galleryorientationchanged", this );
+				self.orientationEventFire = false;
+			}
+		},
+		_orientationHandler: function() {
+			var self = this;
+			self.refresh();
+			self.orientationEventFire = true;
+		},
+		refresh: function ( start_index ) {
+			this._update();
+
+			this._hide();
+
+			if ( start_index === undefined ) {
+				start_index = this.index;
+			}
+			if ( start_index < 0 ) {
+				start_index = 0;
+			}
+			if ( start_index >= this.images.length ) {
+				start_index = this.images.length - 1;
+			}
+
+			this.index = start_index;
+
+			this._show();
+
+			return this.index;
+		},
+
+		add: function ( file ) {
+			this.images_hold.push( file );
+		},
+
+		remove: function ( index ) {
+			var temp_img;
+
+			if ( index === undefined ) {
+				index = this.index;
+			}
+
+			if ( index < 0 || index >= this.images.length ) {
+				return;
+			}
+
+			if ( index == this.index ) {
+				temp_img = this.cur_img;
+
+				if ( this.index == 0 ) {
+					this.direction = 1;
+				} else if ( this.index == this.images.length - 1 ) {
+					this.direction = -1;
+				}
+
+				if ( this.direction < 0 ) {
+					this.cur_img = this.prev_img;
+					this.prev_img = this.prev_img.prev();
+					if ( this.prev_img.length ) {
+						this._moveLeft( this.prev_img, -this.window_width + 'px' );
+						this._attach( index - 2, this.prev_img );
+					}
+					this.index--;
+				} else {
+					this.cur_img = this.next_img;
+					this.next_img = this.next_img.next();
+					if ( this.next_img.length ) {
+						this._moveLeft( this.next_img, this.window_width + 'px' );
+						this._attach( index + 2, this.next_img );
+					}
+				}
+				this._moveLeft( this.cur_img, '0px', this.options.duration );
+
+			} else if ( index == this.index - 1 ) {
+				temp_img = this.prev_img;
+				this.prev_img = this.prev_img.prev();
+				if ( this.prev_img.length ) {
+					this._moveLeft( this.prev_img, -this.window_width + 'px' );
+					this._attach( index - 1, this.prev_img );
+				}
+				this.index--;
+
+			} else if ( index == this.index + 1 ) {
+				temp_img = this.next_img;
+				this.next_img = this.next_img.next();
+				if ( this.next_img.length ) {
+					this._moveLeft( this.next_img, this.window_width + 'px' );
+					this._attach( index + 1, this.next_img );
+				}
+
+			} else {
+				temp_img = $( 'div' ).find( '.ui-gallery-bg:eq(' + index + ')' );
+			}
+
+			this.images.splice( index, 1 );
+			temp_img.detach();
+		},
+
+		empty: function () {
+			this.images.splice( 0, this.images.length );
+			this.container.find('.ui-gallery-bg').detach();
+		},
+
+		length: function () {
+			return this.images.length;
+		},
+
+		value: function ( index ) {
+			if ( index === undefined ) {
+				return this.index;
+			}
+
+			this.refresh( index );
+		},
+
+		unbind: function() {
+			$.each( this._globalHandlers, function( idx, value ) {
+				value.src.unbind( value.handler );
+			});
+		},
+
+		destory: function() {
+			this.unbind();
+		}
+
+	}); /* End of widget */
+
+	// auto self-init widgets
+	$( document ).bind( "pagecreate create", function ( e ) {
+		$( e.target ).find( ":jqmData(role='gallery')" ).gallery();
+	});
+
+	$( document ).bind( "pageshow", function ( e ) {
+		$( e.target ).find( ":jqmData(role='gallery')" ).gallery( 'show' );
+	});
+
+	$( document ).bind( "pagebeforehide", function ( e ) {
+		$( e.target ).find( ":jqmData(role='gallery')" ).gallery( 'hide' );
+	} );
+
+	$( document ).bind( "pageremove", function ( e ) {
+		//unbind resize and orientationchange events
+		$( e.target ).find( ":jqmData(role='gallery')" ).gallery( 'unbind' );
+	});
+
+}( jQuery, this ) );
+
+//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
+} );
+//>>excludeEnd("jqmBuildExclude");

http://git-wip-us.apache.org/repos/asf/cordova-tizen/blob/4ebce38e/samples/TizenWebUI-sample-v1/tizen-web-ui-fw/latest/js/modules/widgets/jquery.mobile.tizen.gallery3d.js
----------------------------------------------------------------------
diff --git a/samples/TizenWebUI-sample-v1/tizen-web-ui-fw/latest/js/modules/widgets/jquery.mobile.tizen.gallery3d.js b/samples/TizenWebUI-sample-v1/tizen-web-ui-fw/latest/js/modules/widgets/jquery.mobile.tizen.gallery3d.js
new file mode 100644
index 0000000..cded9f4
--- /dev/null
+++ b/samples/TizenWebUI-sample-v1/tizen-web-ui-fw/latest/js/modules/widgets/jquery.mobile.tizen.gallery3d.js
@@ -0,0 +1,1503 @@
+//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
+//>>description: 3D photo gallery widget.
+//>>label: Gallery3d
+//>>group: Tizen:Widgets
+
+define( [ 
+	'jquery',
+	"jqm/jquery.mobile.widget",
+	'libs/jquery.easing.1.3',
+	"libs/gl-matrix",
+	"./components/imageloader",
+	"./components/motionpath",
+	"./components/webgl"
+	], function ( jQuery ) {
+
+//>>excludeEnd("jqmBuildExclude");
+
+/* ***************************************************************************
+	Flora License
+
+	Version 1.1, April, 2013
+
+	http://floralicense.org/license/
+
+	TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+	1. Definitions.
+
+	"License" shall mean the terms and conditions for use, reproduction,
+	and distribution as defined by Sections 1 through 9 of this document.
+
+	"Licensor" shall mean the copyright owner or entity authorized by
+	the copyright owner that is granting the License.
+
+	"Legal Entity" shall mean the union of the acting entity and
+	all other entities that control, are controlled by, or are
+	under common control with that entity. For the purposes of
+	this definition, "control" means (i) the power, direct or indirect,
+	to cause the direction or management of such entity,
+	whether by contract or otherwise, or (ii) ownership of fifty percent (50%)
+	or more of the outstanding shares, or (iii) beneficial ownership of
+	such entity.
+
+	"You" (or "Your") shall mean an individual or Legal Entity
+	exercising permissions granted by this License.
+
+	"Source" form shall mean the preferred form for making modifications,
+	including but not limited to software source code, documentation source,
+	and configuration files.
+
+	"Object" form shall mean any form resulting from mechanical
+	transformation or translation of a Source form, including but
+	not limited to compiled object code, generated documentation,
+	and conversions to other media types.
+
+	"Work" shall mean the work of authorship, whether in Source or Object form,
+	made available under the License, as indicated by a copyright notice
+	that is included in or attached to the work (an example is provided
+	in the Appendix below).
+
+	"Derivative Works" shall mean any work, whether in Source or Object form,
+	that is based on (or derived from) the Work and for which the editorial
+	revisions, annotations, elaborations, or other modifications represent,
+	as a whole, an original work of authorship. For the purposes of this License,
+	Derivative Works shall not include works that remain separable from,
+	or merely link (or bind by name) to the interfaces of, the Work and
+	Derivative Works thereof.
+
+	"Contribution" shall mean any work of authorship, including the original
+	version of the Work and any modifications or additions to that Work or
+	Derivative Works thereof, that is intentionally submitted to Licensor
+	for inclusion in the Work by the copyright owner or by an individual or
+	Legal Entity authorized to submit on behalf of the copyright owner.
+	For the purposes of this definition, "submitted" means any form of
+	electronic, verbal, or written communication sent to the Licensor or
+	its representatives, including but not limited to communication on
+	electronic mailing lists, source code control systems, and issue
+	tracking systems that are managed by, or on behalf of, the Licensor
+	for the purpose of discussing and improving the Work, but excluding
+	communication that is conspicuously marked or otherwise designated
+	in writing by the copyright owner as "Not a Contribution."
+
+	"Contributor" shall mean Licensor and any individual or Legal Entity
+	on behalf of whom a Contribution has been received by Licensor and
+	subsequently incorporated within the Work.
+
+	"Tizen Certified Platform" shall mean a software platform that complies
+	with the standards set forth in the Tizen Compliance Specification
+	and passes the Tizen Compliance Tests as defined from time to time
+	by the Tizen Technical Steering Group and certified by the Tizen
+	Association or its designated agent.
+
+	2. Grant of Copyright License.  Subject to the terms and conditions of
+	this License, each Contributor hereby grants to You a perpetual,
+	worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+	copyright license to reproduce, prepare Derivative Works of,
+	publicly display, publicly perform, sublicense, and distribute the
+	Work and such Derivative Works in Source or Object form.
+
+	3. Grant of Patent License.  Subject to the terms and conditions of
+	this License, each Contributor hereby grants to You a perpetual,
+	worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+	(except as stated in this section) patent license to make, have made,
+	use, offer to sell, sell, import, and otherwise transfer the Work
+	solely as incorporated into a Tizen Certified Platform, where such
+	license applies only to those patent claims licensable by such
+	Contributor that are necessarily infringed by their Contribution(s)
+	alone or by combination of their Contribution(s) with the Work solely
+	as incorporated into a Tizen Certified Platform to which such
+	Contribution(s) was submitted. If You institute patent litigation
+	against any entity (including a cross-claim or counterclaim
+	in a lawsuit) alleging that the Work or a Contribution incorporated
+	within the Work constitutes direct or contributory patent infringement,
+	then any patent licenses granted to You under this License for that
+	Work shall terminate as of the date such litigation is filed.
+
+	4. Redistribution.  You may reproduce and distribute copies of the
+	Work or Derivative Works thereof pursuant to the copyright license
+	above, in any medium, with or without modifications, and in Source or
+	Object form, provided that You meet the following conditions:
+
+	  1. You must give any other recipients of the Work or Derivative Works
+		 a copy of this License; and
+	  2. You must cause any modified files to carry prominent notices stating
+		 that You changed the files; and
+	  3. You must retain, in the Source form of any Derivative Works that
+		 You distribute, all copyright, patent, trademark, and attribution
+		 notices from the Source form of the Work, excluding those notices
+		 that do not pertain to any part of the Derivative Works; and
+	  4. If the Work includes a "NOTICE" text file as part of its distribution,
+		 then any Derivative Works that You distribute must include a readable
+		 copy of the attribution notices contained within such NOTICE file,
+		 excluding those notices that do not pertain to any part of
+		 the Derivative Works, in at least one of the following places:
+		 within a NOTICE text file distributed as part of the Derivative Works;
+		 within the Source form or documentation, if provided along with the
+		 Derivative Works; or, within a display generated by the Derivative Works,
+		 if and wherever such third-party notices normally appear.
+		 The contents of the NOTICE file are for informational purposes only
+		 and do not modify the License.
+
+	You may add Your own attribution notices within Derivative Works
+	that You distribute, alongside or as an addendum to the NOTICE text
+	from the Work, provided that such additional attribution notices
+	cannot be construed as modifying the License. You may add Your own
+	copyright statement to Your modifications and may provide additional or
+	different license terms and conditions for use, reproduction, or
+	distribution of Your modifications, or for any such Derivative Works
+	as a whole, provided Your use, reproduction, and distribution of
+	the Work otherwise complies with the conditions stated in this License.
+
+	5. Submission of Contributions. Unless You explicitly state otherwise,
+	any Contribution intentionally submitted for inclusion in the Work
+	by You to the Licensor shall be under the terms and conditions of
+	this License, without any additional terms or conditions.
+	Notwithstanding the above, nothing herein shall supersede or modify
+	the terms of any separate license agreement you may have executed
+	with Licensor regarding such Contributions.
+
+	6. Trademarks.  This License does not grant permission to use the trade
+	names, trademarks, service marks, or product names of the Licensor,
+	except as required for reasonable and customary use in describing the
+	origin of the Work and reproducing the content of the NOTICE file.
+
+	7. Disclaimer of Warranty. Unless required by applicable law or
+	agreed to in writing, Licensor provides the Work (and each
+	Contributor provides its Contributions) on an "AS IS" BASIS,
+	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+	implied, including, without limitation, any warranties or conditions
+	of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+	PARTICULAR PURPOSE. You are solely responsible for determining the
+	appropriateness of using or redistributing the Work and assume any
+	risks associated with Your exercise of permissions under this License.
+
+	8. Limitation of Liability. In no event and under no legal theory,
+	whether in tort (including negligence), contract, or otherwise,
+	unless required by applicable law (such as deliberate and grossly
+	negligent acts) or agreed to in writing, shall any Contributor be
+	liable to You for damages, including any direct, indirect, special,
+	incidental, or consequential damages of any character arising as a
+	result of this License or out of the use or inability to use the
+	Work (including but not limited to damages for loss of goodwill,
+	work stoppage, computer failure or malfunction, or any and all
+	other commercial damages or losses), even if such Contributor
+	has been advised of the possibility of such damages.
+
+	9. Accepting Warranty or Additional Liability. While redistributing
+	the Work or Derivative Works thereof, You may choose to offer,
+	and charge a fee for, acceptance of support, warranty, indemnity,
+	or other liability obligations and/or rights consistent with this
+	License. However, in accepting such obligations, You may act only
+	on Your own behalf and on Your sole responsibility, not on behalf
+	of any other Contributor, and only if You agree to indemnify,
+	defend, and hold each Contributor harmless for any liability
+	incurred by, or claims asserted against, such Contributor by reason
+	of your accepting any such warranty or additional liability.
+
+	END OF TERMS AND CONDITIONS
+
+	APPENDIX: How to apply the Flora License to your work
+
+	To apply the Flora License to your work, attach the following
+	boilerplate notice, with the fields enclosed by brackets "[]"
+	replaced with your own identifying information. (Don't include
+	the brackets!) The text should be enclosed in the appropriate
+	comment syntax for the file format. We also recommend that a
+	file or class name and description of purpose be included on the
+	same "printed page" as the copyright notice for easier
+	identification within third-party archives.
+
+	   Copyright [yyyy] [name of copyright owner]
+
+	   Licensed under the Flora License, Version 1.1 (the "License");
+	   you may not use this file except in compliance with the License.
+	   You may obtain a copy of the License at
+
+		   http://floralicense.org/license/
+
+	   Unless required by applicable law or agreed to in writing, software
+	   distributed under the License is distributed on an "AS IS" BASIS,
+	   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+	   See the License for the specific language governing permissions and
+	   limitations under the License.
+
+
+ * Authors: Hyunsook Park <hy...@samsung.com>
+ *			Wonseop Kim <wo...@samsung.com>
+ */
+
+/**
+ *	The gallery3d widget displays images along a curved path on a 3-dimensional coordinate system.
+ *	To improve performance, the size of image(s) displayed on the screen should be a square(under
+ *	128X128 pixel) as possible. But if a user can't resize the images, this widget supports an image
+ *	resizing feature and he/she can use it with "data-thumbnail-cache" option. ("data-thumbnail-cache"
+ *	option resizes the gallery images under 128x128 pixels and stores the images on a local storage.
+ *	So when a gallery3D widget is re-launched, the widget reuse the storage and a user can improve
+ *	launching time. A browser or web runtime engine should support "Web Storage" feature to use that
+ *	option.)
+ *
+ *	HTML Attributes:
+ *
+ *		data-thumbnail-cache : Determines whether to cache and resize images.
+ *
+ *	APIs:
+ *
+ *		next ( void )
+ *			: This method moves each image forward one by one.
+ *		prev ( void )
+ *			: This method moves each image backward one by one.
+ *		select ( [number] )
+ *			: When the "select" method is called with an argument, the method selects the image of given index.
+ *			If the method is called with no argument, it will return the Javascript object having "src"
+ *			attribute having the selected image's URL.
+ *		add ( object or string [, number] )
+ *			This method adds an image to Gallery3D widget.
+ *			If the second argument isn't inputted, the image is added at the 0th position.
+ *		remove ( [number] )
+ *			: This method deletes an image from Gallery3d widget.
+ *			The argument defines the index of the image to be deleted.
+ *			If an argument isn't inputted, it removes current image.
+ *		clearThumbnailCache ( void )
+ *			: This method clears the cache data of all images when thumbnailCache option is set as 'true'.
+ *		refresh ( void )
+ *			: This method updates and redraws current widget.
+ *		empty ( void )
+ *			: This method removes all of images from Gallery3D widget.
+ *		length ( void )
+ *			: This method gets the number of images.
+ *
+ *	Events:
+ *
+ *		select : Triggered when an image is selected.
+ *
+ *	Examples:
+ *
+ *		<script>
+ *			$( "#gallery3d" ).on( "gallery3dcreate", function () {
+ *				$( "#gallery3d" ).gallery3d( "add", "01.jpg" );
+ *			});
+ *		</script>
+ *		<div id="gallery3d" data-role="gallery3d"></div>
+ */
+
+/**
+	@class Gallery3D
+	The gallery3d widget displays images along a curved path on a 3-dimensional coordinate system.
+	<br/><br/>To add an gallery3d widget to the application, use the following code:
+
+		<script>
+			$( "#gallery3d" ).on( "gallery3dcreate", function () {
+				$( "#gallery3d" ).gallery3d( "add", "01.jpg" );
+			});
+		</script>
+		<div id="gallery3d" data-role="gallery3d"></div>
+*/
+/**
+	@property {Boolean} data-thumbnail-cache
+	Determines whether to cache and resize images.
+	To improve performance, the size of image(s) displayed on the screen should be a square (under 128X128 pixels).
+	"data-thumbnail-cache" option resizes the gallery images under 128x128 pixels and stores the images on a local storage.
+	So when a gallery3D widget is re-launched, the widget reuses the storage and the launching time can be improved.
+	A browser or web runtime engine must support "Web Storage" feature to use this option.
+*/
+/**
+	@event select
+	Triggered when an image is selected.
+
+		<script>
+			$( "#gallery3d" ).on( "gallery3dcreate", function () {
+				$( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )
+					.gallery3d( "add", { src: "2.jpg" } )
+					.gallery3d( "add", { src: "3.jpg" } );
+			}).on( "select", function ( event, data, index ) {
+				// Handle the select event
+				var urlOfImage = data.src, indexOfImage = index;
+			});
+		</script>
+		<div id="gallery3d" data-role="gallery3d"></div>
+*/
+/**
+	@method next
+	This method moves each image forward one by one.
+
+		<script>
+			$( "#gallery3d" ).on( "gallery3dcreate", function () {
+				$( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )
+					.gallery3d( "add", { src: "2.jpg" } )
+					.gallery3d( "add", { src: "3.jpg" } )
+					.gallery3d( "next" );
+			});
+		</script>
+		<div id="gallery3d" data-role="gallery3d"></div>
+*/
+/**
+	@method prev
+	This method moves each image backward one by one.
+
+		<script>
+			$( "#gallery3d" ).on( "gallery3dcreate", function () {
+				$( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )
+					.gallery3d( "add", { src: "2.jpg" } )
+					.gallery3d( "add", { src: "3.jpg" } )
+					.gallery3d( "prev" );
+			});
+		</script>
+		<div id="gallery3d" data-role="gallery3d"></div>
+*/
+/**
+	@method select
+	When the "select" method is called with an argument, the method selects the image of given index.
+	If the method is called with no argument, it will return the Javascript object having "src" attribute having the selected image's URL.
+
+		<script>
+			$( "#gallery3d" ).on( "gallery3dcreate", function () {
+				$( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )
+					.gallery3d( "add", { src: "2.jpg" } )
+					.gallery3d( "add", { src: "3.jpg" } );
+				var selectedImage = $("#gallery3d"). gallery3d( "select" );
+				// selectedImage = { src: "3.jpg" };
+			});
+		</script>
+		<div id="gallery3d" data-role="gallery3d"></div>
+*/
+/**
+	@method add
+	This method adds an image to Gallery3D widget.
+	The first argument is a Javascript object having a "src" attribute or a string of image's path.
+	The second argument is an index of images.
+	If second argument isn't inputted, the image is added at the 0th position.
+
+		<script>
+			$( "#gallery3d" ).on( "gallery3dcreate", function () {
+				$( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )
+					.gallery3d( "add", "2.jpg", 1 );
+			});
+		</script>
+		<div id="gallery3d" data-role="gallery3d"></div>
+*/
+/**
+	@method remove
+	This method deletes an image from Gallery3d widget.
+	The argument defines the index of the image to be deleted.
+	If an argument isn't inputted, it removes current image.
+
+		<script>
+			$( "#gallery3d" ).on( "gallery3dcreate", function () {
+				$( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )
+					.gallery3d( "add", { src: "2.jpg" } )
+					.gallery3d( "add", { src: "3.jpg" } );
+
+				$( "#gallery3d" ).gallery3d( "remove" );
+				$( "#gallery3d" ).gallery3d( "remove", 1 );
+			});
+		</script>
+		<div id="gallery3d" data-role="gallery3d"></div>
+*/
+/**
+	@method clearThumbnailCache
+	This method clears the cache data of all images when thumbnailCache option is set as 'true'
+
+		<script>
+			$( "#gallery3d" ).on( "gallery3dcreate", function () {
+				$( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )
+					.gallery3d( "add", { src: "2.jpg" } )
+					.gallery3d( "add", { src: "3.jpg" } );
+
+				$( "#gallery3d" ).gallery3d( "clearThumbnailCache" );
+			});
+		</script>
+		<div id="gallery3d" data-role="gallery3d" data-thumbnail-cache="true"></div>
+*/
+/**
+	@method refresh
+	This method updates and redraws current widget.
+
+		<script>
+			$( "#gallery3d" ).on( "gallery3dcreate", function () {
+				$( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )
+					.gallery3d( "add", { src: "2.jpg" } )
+					.gallery3d( "add", { src: "3.jpg" } );
+
+				$( "#gallery3d" ).gallery3d( "refresh" );
+			});
+		</script>
+		<div id="gallery3d" data-role="gallery3d"></div>
+*/
+/**
+	@method empty
+	This method removes all of images from Gallery3D widget.
+
+		<script>
+			$( "#gallery3d" ).on( "gallery3dcreate", function () {
+				$( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )
+					.gallery3d( "add", { src: "2.jpg" } )
+					.gallery3d( "add", { src: "3.jpg" } );
+
+				$( "#gallery3d" ).gallery3d( "empty" );
+			});
+		</script>
+		<div id="gallery3d" data-role="gallery3d"></div>
+*/
+/**
+	@method length
+	This method gets the number of images.
+
+		<script>
+			$( "#gallery3d" ).on( "gallery3dcreate", function () {
+				$( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )
+					.gallery3d( "add", { src: "2.jpg" } )
+					.gallery3d( "add", { src: "3.jpg" } );
+
+				var imagesLength = $( "#gallery3d" ).gallery3d( "length" );
+				// imagesLength = 3;
+			});
+		</script>
+		<div id="gallery3d" data-role="gallery3d"></div>
+*/
+
+( function ( $, document, window, undefined ) {
+	function Node() {
+		this.vertices = [
+			-1.0, -1.0, 0.0,
+			1.0, -1.0, 0.0,
+			1.0,  1.0, 0.0,
+			-1.0,  1.0, 0.0
+		];
+		this.textureCoords = [
+			1.0, 0.0,
+			0.0, 0.0,
+			0.0, 1.0,
+			1.0, 1.0
+		];
+		this.normalVectors = [
+			0.0, 0.0, 1.0,
+			0.0, 0.0, 1.0,
+			0.0, 0.0, 1.0,
+			0.0, 0.0, 1.0
+		];
+		this.texture = null;
+		this.textureBuffer = null;
+		this.textureBufferItemSize = 0;
+		this.mashOrder = [];
+		this.mvMatrix = null;
+		this.level = -1;
+		this.targetLevel = 0;
+		this.drawable = false;
+		this.image = null;
+		this.imageID = 0;
+	}
+
+	var isPreInitailization  = false,
+		glMatrix = {},
+		VERTEX_SHADER,
+		FRAGMENT_SHADER,
+		GlArray32,
+		GlArray16,
+		preInitialize = function () {
+			if ( isPreInitailization ) {
+				return;
+			}
+
+			window.initGlMatrix( glMatrix );
+
+			VERTEX_SHADER = [
+				"attribute vec3 aVertexPosition;",
+				"attribute vec2 aTextureCoord;",
+				"attribute vec3 aVertexNormal;",
+				"uniform mat4 uMoveMatrix;",
+				"uniform mat4 uPerspectiveMatrix;",
+				"uniform mat3 nNormalMatrix;",
+				"uniform vec3 uAmbientColor;",
+				"uniform vec3 uLightDirection;",
+				"uniform vec3 uDirectionColor;",
+				"uniform vec3 uLightDirection_first;",
+				"uniform vec3 uLightDirection_second;",
+				"varying vec2 vTextureCoord;",
+				"varying vec3 vLightWeight;",
+				"varying vec4 vFogWeight;",
+
+				"void main(void) {",
+				"	vec4 v_Position = uMoveMatrix * vec4(aVertexPosition, 1.0);",
+				"	gl_Position = uPerspectiveMatrix * v_Position;",
+				"	vTextureCoord = aTextureCoord;",
+				"	float fog = 1.0 - ((gl_Position.z + 1.5) / 60.0);",
+				"	vFogWeight = clamp( vec4( fog, fog, fog, 1.0), 0.6, 1.0);",
+				"	vec3 transNormalVector = nNormalMatrix * aVertexNormal;",
+
+				"	float vLightWeightFirst = 0.0;",
+				"	float vLightWeightSecond = max( dot(transNormalVector, uLightDirection_second), 0.0 );",
+
+				"	vLightWeight = uAmbientColor + uDirectionColor * vLightWeightSecond;",
+				"}"
+			].join( "\n" );
+
+			FRAGMENT_SHADER = [
+				"precision mediump float;",
+				"varying vec2 vTextureCoord;",
+				"varying vec3 vLightWeight;",
+				"uniform sampler2D uSampler;",
+				"varying vec4 vFogWeight;",
+
+				"void main(void) {",
+				"	vec4 TextureColor;",
+				"	if ( vTextureCoord.s <= 0.01 || vTextureCoord.s >= 0.99 || vTextureCoord.t <= 0.01 || vTextureCoord.t >= 0.99 ) {",
+				"		TextureColor = vec4(1.0, 1.0, 1.0, 0.5);",
+				"	} else {",
+				"		TextureColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));",
+				"	}",
+				"	TextureColor *= vFogWeight;",
+				"	gl_FragColor = vec4(TextureColor.rgb * vLightWeight, TextureColor.a);",
+				"}"
+			].join( "\n" );
+
+			GlArray32 = ( typeof window.Float32Array !== "undefined" ?
+					window.Float32Array :
+						( typeof window.WebGLFloatArray !== "undefined" ? window.WebGLFloatArray : Array ) );
+
+			GlArray16 = ( typeof window.Uint16Array !== "undefined" ? window.Uint16Array : Array );
+
+			isPreInitailization = true;
+		},
+		degreeToRadian = function ( degree ) {
+			return degree * Math.PI / 180;
+		},
+		getContext3D = function ( canvas ) {
+			var gl, i,
+				contextNames = [ "experimental-webgl", "webkit-3d", "webgl", "moz-webgl" ];
+
+			for ( i = 0; i < contextNames.length; i += 1 ) {
+				try {
+					gl = canvas.getContext( contextNames[i] );
+					if ( gl ) {
+						break;
+					}
+				} catch ( e ) {
+					$( canvas ).html( "Unfortunately, there's a WebGL compatibility problem. </br> You may want to check your system settings." );
+					return;
+				}
+			}
+			return gl;
+		},
+		requestAnimationFrame = function ( callback ) {
+			var id = window.setTimeout( callback, 1000 / 60 );
+			return id;
+		},
+		cancelAnimationFrame = function ( id ) {
+			window.clearTimeout( id );
+		};
+
+	$.widget( "tizen.gallery3d", $.mobile.widget, {
+		options: {
+			thumbnailCache:	false
+		},
+
+		_MAX_ITEM_COUNT: 28,
+		_ANIMATION_END: 999,
+		_DURATION_DEFAULT: 300,
+		_DURATION_FIRST: 1600,
+		_VIEWPORT_WIDTH: 1024,
+		_VIEWPORT_HEIGHT: 456,
+		_DIRECTION_LEFT: -1,
+		_DIRECTION_RIGHT: +1,
+
+		_gl: null,
+		_shaderProgram : null,
+		_positionBuffer : null,
+		_textureCoordBuffer : null,
+		_normalVectorBuffer : null,
+		_nodes: null,
+		_pMatrix : null,
+		_animationID: 0,
+		_dragInterval : 0,
+		_startTime : 0,
+		_sumTime : 0,
+		_lightsPositionStack : [
+			[0.0, 0.0, -1.0],	// back
+			[-0.2, 0.0, 0.7]	// front
+		],
+		_path: null,
+		_swipeThresholdOfBasetimeGap: ( $.support.touch ? 30 : 70 ),
+		_swipeThresholdOfSensitivity: ( $.support.touch ? 2.0 : 10.0 ),
+		_canvas: null,
+		_imageList: [],
+		_maxDrawLength: 0,
+		_firstImageNumber: 0,
+		_lastImageNumber: 0,
+		_operationQueue: [],
+
+		_create: function () {
+			var self = this,
+				view = self.element,
+				option = self.options;
+
+			preInitialize();
+
+			self._canvas = $( "<canvas class='ui-gallery3d-canvas'></canvas>" );
+
+			view.addClass( "ui-gallery3d" ).append( self._canvas );
+			self._addBehavier();
+
+			self._dragInterval = 1000 / 30;	// 30fps
+
+			$.each( self.options, function ( key, value ) {
+				self.options[ key ] = undefined;
+				self._setOption( key, value );
+			});
+		},
+
+		destroy: function () {
+			this._final();
+			$.mobile.widget.prototype.destroy.call( this );
+		},
+
+		_setOption: function ( key, value ) {
+			switch ( key ) {
+			case "thumbnailCache" :
+				if ( typeof value === "string" ) {
+					value = ( value === "true" ) ? true : false;
+				} else {
+					value = !!value;
+				}
+				this._reset();
+				break;
+			}
+
+			$.mobile.widget.prototype._setOption.call( this, key, value );
+		},
+
+		_init: function ( canvas ) {
+			var self = this,
+				pathPoints = [
+					[40, 0, -48],
+					[-12, 0, -40],	// contorl Point of Point1
+					[24, 0, -9],		// contorl Point of Point2
+					[-5, 0, -5]
+				],
+				i;
+
+			canvas = canvas || self._canvas;
+
+			if ( !canvas ) {
+				return;
+			}
+
+			self._gl = self._gl || self._initGL( canvas[0] );
+			if ( !self._gl ) {
+				return;
+			}
+
+			if ( !self._imageList ) {
+				return;
+			}
+
+			self._shaderProgram = self._shaderProgram || self._initShader( self._gl );
+			if ( !self._shaderProgram ) {
+				return;
+			}
+
+			if ( self._imageList.length > self._MAX_ITEM_COUNT ) {
+				self._firstImageNumber = self._imageList.length - 1;
+				self._lastImageNumber = self._MAX_ITEM_COUNT - 1;
+			}
+
+			self._nodes = self._initBuffers( self._gl, self._shaderProgram );
+
+			self._initTextures( self._gl, self._nodes );
+
+			self._path = $.motionpath( "bezier2d", {
+				points: pathPoints,
+				maxLevel: self._MAX_ITEM_COUNT
+			} );
+
+			for ( i = 0; i < self._nodes.length; i += 1 ) {
+				self._path.levels[i] = self._path.levels[i + 1] || 0;
+				self._nodes[i].level = i;
+			}
+
+			this._setPosition( self._ANIMATION_END, this._DIRECTION_RIGHT );
+
+			while ( this._operationQueue.length ) {
+				this._setPosition( self._ANIMATION_END, this._operationQueue.shift() );
+			}
+		},
+
+		_final: function ( canvas ) {
+			var self = this,
+				gl = self._gl;
+
+			if ( !gl ) {
+				return;
+			}
+
+			self._stop();
+
+			canvas = canvas || self._canvas;
+
+			$( self._nodes ).each( function ( i ) {
+				var node = self._nodes[i];
+				gl.deleteTexture( node.texture );
+				node.texture = null;
+			});
+			self._nodes = null;
+
+			gl.deleteBuffer( self._positionBuffer );
+			self._positionBuffer = null;
+			gl.deleteBuffer( self._textureCoordBuffer );
+			self._textureCoordBuffer = null;
+			gl.deleteBuffer( self._normalVectorBuffer );
+			self._normalVectorBuffer = null;
+
+			$.webgl.shader.deleteShaders( gl );
+			gl.deleteProgram( self._shaderProgram );
+			self._shaderProgram = null;
+
+			self._gl = gl = null;
+		},
+
+		_addBehavier : function () {
+			var self = this,
+				view = self.element,
+				canvas = self._canvas,
+				touchStartEvt = ( $.support.touch ? "touchstart" : "mousedown" ),
+				touchMoveEvt = ( $.support.touch ? "touchmove" : "mousemove" ) + ".gallery3d",
+				touchEndEvt = ( $.support.touch ? "touchend" : "mouseup" ) + ".gallery3d",
+				$document = $( document );
+
+			canvas.on( "webglcontextlost", function ( e ) {
+				e.preventDefault();
+			}).on( "webglcontextrestored", function ( e ) {
+				self._init();
+			}).on( touchStartEvt, function ( e ) {
+				var i = 0,
+					startX = 0,
+					deltaMaxSteps = 20,
+					deltas = [ deltaMaxSteps ],
+					deltaTimes = [ deltaMaxSteps ],
+					deltaIndex = 0,
+					dragValue = 0,
+					dragDirection = false,
+					prevTime = 0;
+
+				e.preventDefault();
+				e.stopPropagation();
+
+				if ( self._imageList.length <= 1 ) {
+					return;
+				}
+
+				self._stop();
+
+				startX =  $.support.touch ? e.originalEvent.changedTouches[0].pageX : e.pageX;
+				prevTime = $.now();
+
+				for ( i = 0; i < deltaMaxSteps; i += 1 ) {
+					deltas[i] = startX;
+					deltaTimes[i] = $.now();
+				}
+
+				deltaIndex += 1;
+
+				view.on( touchMoveEvt, function ( e ) {
+					var x, dx, interval;
+
+					e.preventDefault();
+					e.stopPropagation();
+
+					x =  $.support.touch ? e.originalEvent.changedTouches[0].pageX : e.pageX;
+					dx = startX - x;
+
+					deltas[deltaIndex] = x;
+					deltaTimes[deltaIndex] = $.now();
+					interval = deltaTimes[deltaIndex] - prevTime;
+
+					deltaIndex = ( deltaIndex + 1 ) % deltaMaxSteps;
+
+					// Validation of drag
+					if ( Math.abs( dx ) >= 10 && interval >= self._dragInterval ) {
+						if ( dragDirection !== ( ( dx < 0 ) ? self._DIRECTION_RIGHT : self._DIRECTION_LEFT ) ) {
+							dragValue = 0;
+							dragDirection = ( dx < 0 ) ? self._DIRECTION_RIGHT : self._DIRECTION_LEFT;
+						}
+
+						dragValue += Math.abs( dx ) / 100;
+						if ( dragValue >= 1 ) {
+							self._setPosition( self._ANIMATION_END, dragDirection );
+							dragValue = 0;
+						} else {
+							self._setPosition( dragValue, dragDirection );
+						}
+						self._drawScene();
+						startX = x;
+						prevTime = $.now();
+					}
+				}).on( touchEndEvt, function ( e ) {
+					var baseTime = 0,
+						recent = -1,
+						index = 0,
+						previous = 0,
+						baseTimeRatio = 0,
+						fx = 0,
+						lastX = 0,
+						velocityX = 0,
+						dx = 0,
+						isSwipe = true,
+						direction;
+
+					e.preventDefault();
+					e.stopPropagation();
+
+					// Validation of swipe
+					baseTime = $.now() - self._swipeThresholdOfBasetimeGap;
+					lastX = $.support.touch ? e.originalEvent.changedTouches[0].pageX : e.pageX;
+					dx = startX - lastX;
+					startX = 0;
+					for ( i = 0; i < deltaMaxSteps; i += 1 ) {
+						index = ( deltaIndex + i ) % deltaMaxSteps;
+						if ( deltaTimes[index] > baseTime ) {
+							recent = index;
+							break;
+						}
+					}
+					if ( recent < 0 ) {
+						isSwipe = false;
+					}
+
+					if ( isSwipe ) {
+						previous = recent;
+						for ( i = 0; i < deltaMaxSteps; i += 1 ) {
+							previous = ( previous - 1 + deltaMaxSteps ) % deltaMaxSteps;
+							if ( deltaTimes[previous] < deltaTimes[recent] ) {
+								break;
+							}
+						}
+						// too slow or too fast
+						if ( i === deltaMaxSteps || baseTime < deltaTimes[previous] ) {
+							isSwipe = false;
+						}
+					}
+
+					if ( isSwipe ) {
+						baseTimeRatio = ( baseTime - deltaTimes[previous] ) / ( deltaTimes[recent] - deltaTimes[previous] );
+						fx = ( 1.0 - baseTimeRatio ) * deltas[previous] + baseTimeRatio * deltas[recent];
+						if ( Math.abs( fx - lastX ) < self._swipeThresholdOfSensitivity ) {
+							fx = lastX;
+						}
+						velocityX = parseInt( ( lastX - fx ) / ( $.now() - baseTime ), 10 );
+					}
+
+					if ( isSwipe && velocityX ) {
+						direction = ( velocityX < 0 ) ? self._DIRECTION_LEFT : self._DIRECTION_RIGHT;
+						self._run( direction, Math.abs( velocityX ), dragValue );
+					} else if ( dragDirection !== 0 && dragValue ) {
+						self._animate( null, self._DURATION_DEFAULT * ( 1 - dragValue ), dragDirection, 0, dragValue );
+					}
+
+					view.off( ".gallery3d" );
+					$document.off( ".gallery3d" );
+				});
+
+				$document.on( touchMoveEvt + " " + touchEndEvt, function () {
+					view.trigger( touchEndEvt );
+				});
+			});
+		},
+
+		// ----------------------------------------------------------
+		// WebGL
+		// ----------------------------------------------------------
+		_initGL: function ( canvas ) {
+			var self = this,
+				mat4 = glMatrix.mat4,
+				gl;
+
+			gl = getContext3D( canvas );
+			if ( !gl ) {
+				return null;
+			}
+
+			gl.enable( gl.BLEND );
+			gl.blendFunc( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA );
+
+			gl.enable( gl.DEPTH_TEST );
+			gl.depthFunc( gl.LEQUAL );
+
+			canvas.width = self._VIEWPORT_WIDTH;
+			canvas.height = self._VIEWPORT_HEIGHT;
+			gl.viewportWidth = canvas.width;
+			gl.viewportHeight = canvas.height;
+			gl.viewport( 0, 0, gl.viewportWidth, gl.viewportHeight );
+			self._pMatrix = mat4.create();
+			mat4.perspective( 40, gl.viewportWidth / gl.viewportHeight, 0.1, 10000.0, self._pMatrix );
+
+			gl.clearColor( 0.15, 0.15, 0.15, 1.0 );
+			gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
+
+			return gl;
+		},
+
+		_initShader : function ( gl ) {
+			var self = this,
+				shaderProgram;
+
+			shaderProgram = $.webgl.shader.addShaderProgram( self._gl, VERTEX_SHADER, FRAGMENT_SHADER );
+			gl.useProgram( shaderProgram );
+
+			shaderProgram.vertexPositionAttr = gl.getAttribLocation( shaderProgram, "aVertexPosition" );
+			gl.enableVertexAttribArray( shaderProgram.vertexPositionAttr );
+
+			shaderProgram.textureCoordAttr = gl.getAttribLocation( shaderProgram, "aTextureCoord" );
+			gl.enableVertexAttribArray( shaderProgram.textureCoordAttr );
+
+			// Set light normal vectors for lighting~
+			shaderProgram.vertexNormalAttr = gl.getAttribLocation( shaderProgram, "aVertexNormal" );
+			gl.enableVertexAttribArray( shaderProgram.vertexNormalAttr );
+
+			shaderProgram.perspectiveMU = gl.getUniformLocation( shaderProgram, "uPerspectiveMatrix");
+			shaderProgram.transformMU = gl.getUniformLocation( shaderProgram, "uMoveMatrix");
+			shaderProgram.sampleUniform = gl.getUniformLocation( shaderProgram, "uSampler");
+
+			// Set light variables~
+			shaderProgram.normalMU = gl.getUniformLocation( shaderProgram, "nNormalMatrix");
+			shaderProgram.ambientColorU = gl.getUniformLocation( shaderProgram, "uAmbientColor");
+			shaderProgram.lightDirU_first = gl.getUniformLocation( shaderProgram, "uLightDirection_first");
+			shaderProgram.lightDirU_second = gl.getUniformLocation( shaderProgram, "uLightDirection_second");
+			shaderProgram.directionColorU = gl.getUniformLocation( shaderProgram, "uDirectionColor");
+
+			return shaderProgram;
+		},
+
+		_initBuffers: function ( gl, shaderProgram ) {
+			var self = this,
+				i = 0,
+				mashBase = 0,
+				vertices = [],
+				textureCoords = [],
+				normalVectors = [],
+				nodes = [],
+				maxDrawLength = self._MAX_ITEM_COUNT;
+
+			for ( i = 0; i < self._imageList.length + 1; i += 1 ) {
+				nodes[i] = new Node();
+				$.merge( vertices, nodes[i].vertices );
+				$.merge( textureCoords, nodes[i].textureCoords );
+				$.merge( normalVectors, nodes[i].normalVectors );
+
+				nodes[i].textureBuffer = gl.createBuffer();
+				gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, nodes[i].textureBuffer );
+				mashBase = i * 4;
+				nodes[i].meshOrder = [
+					mashBase, mashBase + 1, mashBase + 2,
+					mashBase + 2, mashBase + 3, mashBase
+				];
+				gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new GlArray16( nodes[i].meshOrder ), gl.STATIC_DRAW );
+				gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null ); // release buffer memory
+				nodes[i].textureBufferItemSize = 6;
+			}
+
+			self._positionBuffer = $.webgl.buffer.attribBufferData( gl, new GlArray32( vertices ) );
+			self._positionBuffer.itemSize = 3;
+
+			self._textureCoordBuffer = $.webgl.buffer.attribBufferData( gl, new GlArray32( textureCoords ) );
+			self._textureCoordBuffer.itemSize = 2;
+
+			self._normalVectorBuffer = $.webgl.buffer.attribBufferData( gl, new GlArray32( normalVectors ) ); // Vertex's normal vector for Direction light
+			self._normalVectorBuffer.itemSize = 3;
+
+			// Ambient light
+			gl.uniform3f( shaderProgram.ambientColorU, 0.1, 0.1, 0.1 );
+			// Direcntion light
+			gl.uniform3f( shaderProgram.directionColorU, 1.0, 1.0, 1.0 );
+
+			return nodes;
+		},
+
+		// ----------------------------------------------------------
+		// Texture
+		// ----------------------------------------------------------
+		_initTextures: function ( gl, nodes ) {
+			var self = this;
+
+			$( nodes ).each( function ( i ) {
+				var node = nodes[i],
+					url;
+
+				if ( !self._imageList[i] ) {
+					return false;
+				}
+
+				url = self._imageList[i].src;
+				node.texture = gl.createTexture();
+				self._loadImage( url, i, i, gl, nodes );
+			});
+		},
+
+		_loadImage: function ( url, i, imageID, gl, nodes ) {
+			var self = this,
+				isMipmap = false,
+				image,
+				node;
+
+			gl = gl || self._gl;
+			nodes = nodes || self._nodes;
+			isMipmap = isMipmap || false;
+			node = nodes[i];
+			node.image = node.image || new Image();
+			node.imageID = imageID;
+
+			$( node.image ).one( "load", function ( e ) {
+				self._bindTexture( gl, node, this, isMipmap );
+
+				if ( !self._animationID ) {
+					self._setPosition( 0, 0 );
+				}
+			});
+
+			if ( self.options.thumbnailCache ) {
+				$.imageloader.getThumbnail( url, function ( result ) {
+					if ( result === "NOT_FOUND_ERR" ) {
+						$.imageloader.setThumbnail( url, function ( result ) {
+							if ( result && result.length > 30 ) {
+								node.image.src = result;
+								isMipmap = true;
+							} else {
+								node.image.src = url;
+							}
+						});
+					} else if ( result && result.length > 30 ) {
+						node.image.src = result;
+						isMipmap = true;
+					} else {
+						node.image.src = url;
+					}
+				});
+			} else {
+				node.image.src = url;
+			}
+		},
+
+		_bindTexture: function ( gl, node, image, isMipmap ) {
+			if ( !node || !node.texture ) {
+				return;
+			}
+
+			gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, true );
+
+			gl.bindTexture( gl.TEXTURE_2D, node.texture );
+			gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image );
+
+			if ( isMipmap ) {
+				gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR );
+				gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST );
+				gl.generateMipmap( gl.TEXTURE_2D );
+			} else {
+				gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR );
+				gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR );
+			}
+
+			gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );
+			gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );
+
+			node.texture.loaded = true;
+
+			// release texture memory
+			gl.bindTexture( gl.TEXTURE_2D, null );
+		},
+
+		// ----------------------------------------------------------
+		// rendering
+		// ----------------------------------------------------------
+		_setPosition: function ( progress, direction ) {
+			var self = this,
+				mat4 = glMatrix.mat4,
+				nodes = self._nodes,
+				imageList = self._imageList,
+				imageListLength = imageList.length,
+				itemCount = self._MAX_ITEM_COUNT,
+				displayLength = ( imageListLength > itemCount ) ? itemCount : imageListLength,
+				nextLevelLenth = 0,
+				i = 0,
+				t = 0,
+				position = 0,
+				angle = 0,
+				current = 0,
+				next = 0,
+				nextLevel = 0,
+				path = self._path,
+				nextImageID = 0;
+
+			nextLevelLenth = ( direction >= 0 ) ? displayLength + 1 : displayLength;
+
+			if ( !nodes[i].level ) {
+				nodes[i].level = displayLength;
+			}
+
+			for ( i = 0; i < displayLength; i += 1 ) {
+				if ( !nodes[i].mvMatrix ) {
+					nodes[i].mvMatrix = mat4.create();
+				}
+
+				if ( direction > 0 && nodes[i].level >= displayLength ) {
+					nodes[i].level = 0;
+				}
+
+				current = path.levels[nodes[i].level];
+				nextLevel = ( nodes[i].level + nextLevelLenth + direction ) % nextLevelLenth;
+				next = path.levels[nextLevel];
+
+				if ( imageListLength > itemCount ) {
+					if ( direction > 0 && nextLevel === 1
+							&& self._firstImageNumber !== nodes[i].imageID ) {
+						self._loadImage( imageList[self._firstImageNumber].src, i, self._firstImageNumber );
+					} else if ( direction < 0 && nextLevel === nextLevelLenth - 1
+							&& self._lastImageNumber !== nodes[i].imageID ) {
+						self._loadImage( imageList[self._lastImageNumber].src, i, self._lastImageNumber );
+					}
+				}
+
+				mat4.identity( nodes[i].mvMatrix );
+				mat4.translate( nodes[i].mvMatrix, [-2.0, -2.0, 1.0] );
+				mat4.rotate( nodes[i].mvMatrix, degreeToRadian( 19 ), [1, 0, 0] );
+
+				t = ( current + ( next - current ) * ( ( progress > 1 ) ? 1 : progress ) );
+
+				if ( progress >= self._ANIMATION_END ) {
+					nodes[i].level = nextLevel || displayLength;
+					t = path.levels[nodes[i].level];
+				}
+
+				if ( ( progress < self._ANIMATION_END )
+						&& ( direction <= 0 && nodes[i].level < 1 ) ) {
+					nodes[i].drawable = false;
+				} else {
+					nodes[i].drawable = true;
+				}
+
+				if ( progress === self._ANIMATION_END && nodes[i].level === 1 ) {
+					self.element.trigger( "select", [imageList[nodes[i].imageID], nodes[i].imageID] );
+				}
+
+				position = path.getPosition( t );
+				angle = path.getAngle( t );
+
+				mat4.translate( nodes[i].mvMatrix, position );
+				mat4.rotate( nodes[i].mvMatrix, angle, [0, 1, 0] );
+			}
+
+			if ( imageListLength > itemCount && progress >= self._ANIMATION_END ) {
+				self._firstImageNumber = ( self._firstImageNumber - direction ) % imageListLength;
+				if ( self._firstImageNumber < 0 ) {
+					self._firstImageNumber = imageListLength - 1;
+				}
+
+				self._lastImageNumber = ( self._lastImageNumber - direction ) % imageListLength;
+				if ( self._lastImageNumber < 0 ) {
+					self._lastImageNumber = imageListLength - 1;
+				}
+			}
+			self._drawScene();
+		},
+
+		_drawScene: function () {
+			if ( !this._gl || !this._shaderProgram ) {
+				return;
+			}
+
+			var self = this,
+				gl = self._gl,
+				shaderProgram = self._shaderProgram,
+				nodes = self._nodes,
+				nodesLength = nodes.length,
+				i;
+
+			gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
+
+			gl.bindBuffer( gl.ARRAY_BUFFER, self._positionBuffer );
+			gl.vertexAttribPointer( shaderProgram.vertexPositionAttr, self._positionBuffer.itemSize, gl.FLOAT, false, 0, 0 );
+
+			gl.bindBuffer( gl.ARRAY_BUFFER, self._textureCoordBuffer );
+			gl.vertexAttribPointer( shaderProgram.textureCoordAttr, self._textureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0 );
+
+			gl.bindBuffer( gl.ARRAY_BUFFER, self._normalVectorBuffer );
+			gl.vertexAttribPointer( shaderProgram.vertexNormalAttr, self._normalVectorBuffer.itemSize, gl.FLOAT, false, 0, 0 );
+
+			for ( i = 0; i < nodesLength; i += 1 ) {
+				if ( nodes[i].drawable ) {
+					self._drawElement( self._pMatrix, nodes[i] );
+				}
+			}
+		},
+
+		_drawElement: function ( perspectiveMatrix, targetNode ) {
+			var self = this,
+				gl = self._gl,
+				vec3 = glMatrix.vec3,
+				mat3 = glMatrix.mat3,
+				mat4 = glMatrix.mat4,
+				shaderProgram = self._shaderProgram,
+				moveMatrix = targetNode.mvMatrix,
+				texture = targetNode.texture,
+				meshIndexBuffer = targetNode.textureBuffer,
+				meshIndexBufferItemSize = targetNode.textureBufferItemSize,
+				lightPositions = self._lightsPositionStack,
+				LightDir,
+				normalMatrix;
+
+			if ( !moveMatrix ) {
+				return;
+			}
+
+			gl.activeTexture( gl.TEXTURE0 );
+			if ( texture && texture.loaded ) {
+				gl.bindTexture( gl.TEXTURE_2D, texture );
+			}
+			gl.uniform1i( shaderProgram.sampleUniform, 0 );
+
+			LightDir = vec3.create();
+			vec3.normalize( lightPositions[0], LightDir );
+			vec3.scale( LightDir, -8 );
+			gl.uniform3fv( shaderProgram.lightDirU_first, LightDir );
+
+			vec3.normalize( lightPositions[1], LightDir );
+			vec3.scale( LightDir, -1 );
+			gl.uniform3fv( shaderProgram.lightDirU_second, LightDir );
+			gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, meshIndexBuffer );
+
+			gl.uniformMatrix4fv( shaderProgram.perspectiveMU, false, perspectiveMatrix );
+			gl.uniformMatrix4fv( shaderProgram.transformMU, false, moveMatrix );
+
+			normalMatrix = mat3.create();
+			mat4.toInverseMat3( moveMatrix, normalMatrix );
+			mat3.transpose( normalMatrix );
+			gl.uniformMatrix3fv( shaderProgram.normalMU, false, normalMatrix );
+
+			gl.drawElements( gl.TRIANGLES, meshIndexBufferItemSize, gl.UNSIGNED_SHORT, 0 );
+
+			// release buffer memory
+			gl.bindBuffer( gl.ARRAY_BUFFER, null );
+			gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null );
+
+			// release texture memory
+			gl.bindTexture( gl.TEXTURE_2D, null );
+		},
+
+		// ----------------------------------------------------------
+		// Animation
+		// ----------------------------------------------------------
+		_animate: function ( easingType, duration, direction, repeatCount, startValue, _removeCount ) {
+			var self = this,
+				timeNow = $.now(),
+				progress,
+				removeCount = 0;
+
+			easingType = easingType || "linear";
+			startValue = startValue || 0;
+			_removeCount = _removeCount || 0;
+
+			if ( self._sumTime >= duration ) {
+				self._setPosition( self._ANIMATION_END, direction );
+				self._stop();
+				return;
+			}
+
+			if ( self._startTime === 0 ) {
+				self._startTime = timeNow;
+			} else {
+				self._sumTime = timeNow - self._startTime;
+				progress = $.easing[ easingType ]( self._sumTime / duration, self._sumTime, startValue, repeatCount + 1, duration );
+				removeCount = parseInt( Math.abs( progress ), 10 );
+
+				if ( _removeCount !== removeCount ) {
+					self._setPosition( self._ANIMATION_END, direction );
+					_removeCount = removeCount;
+
+					if ( ( repeatCount - _removeCount ) >= 0 ) {
+						self._animate( easingType, duration, direction, repeatCount, startValue, _removeCount );
+					} else {
+						self._stop();
+					}
+					return;
+				}
+
+				self._setPosition( progress - _removeCount, direction );
+			}
+
+			self._animationID = requestAnimationFrame( function () {
+				self._animate( easingType, duration, direction, repeatCount, startValue, _removeCount );
+			});
+		},
+
+		_run: function ( direction, repeatCount, startValue ) {
+			var self = this,
+				repeat = repeatCount || 0,
+				duration = self._DURATION_DEFAULT * ( repeat + 1 );
+
+			if ( !self._gl ) {
+				self._operationQueue.push( direction );
+				return;
+			}
+
+			if ( self._imageList.length <= 1 ) {
+				return;
+			}
+
+			startValue = startValue || 0;
+			duration = ( duration >= 0 ) ? duration : 0;
+
+			if ( self._animationID ) {
+				self._setPosition( self._ANIMATION_END, direction );
+				self._stop();
+			}
+
+			self._animate( "easeOutExpo", duration, direction, repeat, startValue );
+		},
+
+		_reset: function () {
+			if ( !this._canvas || !this._gl ) {
+				return;
+			}
+
+			this._final();
+			this._init();
+			this.refresh();
+		},
+
+		_stop: function () {
+			if ( this._animationID ) {
+				cancelAnimationFrame( this._animationID );
+			}
+			this._animationID = 0;
+
+			this._startTime = 0;
+			this._sumTime = 0;
+		},
+
+		next: function () {
+			this._run( this._DIRECTION_LEFT , 0 );
+		},
+
+		prev: function () {
+			this._run( this._DIRECTION_RIGHT, 0 );
+		},
+
+		refresh: function () {
+			var view = this.element,
+				canvas = view.find( "canvas.ui-gallery3d-canvas" );
+
+			if ( canvas.width() !== view.width() ) {
+				canvas.width( view.width() );
+			}
+
+			if ( !this._animationID ) {
+				this._setPosition( 0, 0 );
+			}
+		},
+
+		select: function ( index ) {
+			var nodes = this._nodes,
+				repeat,
+				i,
+				imageID,
+				object = null,
+				target = 0,
+				direction = 0;
+
+			if ( index && this._animationID ) {
+				this._stop();
+			}
+
+			for ( i in nodes ) {
+				if ( nodes[i].level === 1 ) {
+					object = this._imageList[ nodes[i].imageID ];
+					imageID = nodes[i].imageID;
+					break;
+				}
+			}
+
+			if ( !index ) {
+				return object;
+			}
+
+			if ( index < 0 && index >= this._imageList.length ) {
+				return;
+			}
+
+			target = index - imageID;
+			direction = ( target > 0 ) ? this._DIRECTION_LEFT
+				: ( ( target < 0 ) ? this._DIRECTION_RIGHT : 0 );
+			if ( direction ) {
+				this._run( direction, Math.abs( target ) - 1  );
+			}
+		},
+
+		add: function ( item, index ) {
+			if ( !item ) {
+				return;
+			}
+
+			if ( typeof item === "string" ) {
+				item = { "src" : item };
+			}
+
+			index = index || 0;
+			if ( typeof index !== "number" && index < 0
+					&& index >= this._imageList.length ) {
+				return;
+			}
+
+			this._imageList.splice( index, 0, item );
+			if ( this._gl ) {
+				this._reset();
+			}
+		},
+
+		remove: function ( index ) {
+			index = index || 0;
+			if ( typeof index !== "number" && index < 0
+					&& index >= this._imageList.length ) {
+				return;
+			}
+
+			this._imageList.splice( index, 1 );
+			if ( this._gl ) {
+				this._reset();
+			}
+		},
+
+		clearThumbnailCache: function () {
+			if ( !this._nodes || ( this._nodes.length <= 0 ) ) {
+				return;
+			}
+
+			var i, url;
+			for ( i = 0; i < this._imageList.length; i += 1 ) {
+				url = this._imageList[i].src;
+				$.imageloader.removeThumbnail( url );
+			}
+		},
+
+		empty: function () {
+			this._imageList = [];
+			this._reset();
+		},
+
+		length: function () {
+			return this._imageList.length;
+		}
+	});
+
+	$( document ).on( "pagecreate create", function ( e ) {
+		$( ":jqmData(role='gallery3d')" ).gallery3d();
+	}).on( "pagechange", function ( e ) {
+		$( e.target ).find( ".ui-gallery3d" ).gallery3d( "refresh" );
+	});
+
+	$( window ).on( "resize orientationchange", function ( e ) {
+		$( ".ui-page-active" ).find( ".ui-gallery3d" ).gallery3d( "refresh" );
+	});
+
+} ( jQuery, document, window ) );
+
+//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
+} );
+//>>excludeEnd("jqmBuildExclude");

http://git-wip-us.apache.org/repos/asf/cordova-tizen/blob/4ebce38e/samples/TizenWebUI-sample-v1/tizen-web-ui-fw/latest/js/modules/widgets/jquery.mobile.tizen.listdivider.js
----------------------------------------------------------------------
diff --git a/samples/TizenWebUI-sample-v1/tizen-web-ui-fw/latest/js/modules/widgets/jquery.mobile.tizen.listdivider.js b/samples/TizenWebUI-sample-v1/tizen-web-ui-fw/latest/js/modules/widgets/jquery.mobile.tizen.listdivider.js
new file mode 100644
index 0000000..1ad61cb
--- /dev/null
+++ b/samples/TizenWebUI-sample-v1/tizen-web-ui-fw/latest/js/modules/widgets/jquery.mobile.tizen.listdivider.js
@@ -0,0 +1,91 @@
+//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
+//>>description: Divider listitem in listview
+//>>label: List divider
+//>>group: Tizen:Widgets
+
+define( [ 
+	'jquery',
+	"jqm/jquery.mobile.widget"
+	], function ( jQuery ) {
+
+//>>excludeEnd("jqmBuildExclude");
+
+/* ***************************************************************************
+* style : normal, check
+* option :
+*    - folded : decide to show divider press effect or not
+*    - line : decide to draw divider line or not
+*/
+/**
+	@class ListDivider
+	The list divider widget is used as a list separator for grouping lists. List dividers can be used in Tizen as described in the jQueryMobile documentation for list dividers.<br/>
+	To add a list divider widget to the application, use the following code:
+
+		<li data-role="list-divider" data-style="check">
+		<form><input type="checkbox" name="c2line-check1" /></form></li>
+
+	The list divider can define callbacks for events as described in the jQueryMobile documentation for list events. <br/> You can use methods with the list divider as described in the jQueryMobile documentation for list methods.
+
+	@since tizen2.0	
+*/
+/**
+	@property {String} data-style
+	Sets the style of the list divider. The style options are dialogue, check, expandable, and checkexpandable.
+*/
+
+(function ( $, undefined ) {
+	$.widget( "tizen.listdivider", $.mobile.widget, {
+		options: {
+			initSelector: ":jqmData(role='list-divider')",
+			folded : false,
+			listDividerLine : true
+		},
+
+		_create: function () {
+
+			var $listdivider = this.element,
+				openStatus = true,
+				expandSrc,
+				listDividerLine = true,
+				style = $listdivider.attr( "data-style" );
+
+			if ( $listdivider.data("line") === false ) {
+				this.options.listDividerLine = false;
+			}
+
+			if ( $listdivider.data("folded") === true ) {
+				this.options.folded = true;
+			}
+
+			if ( style == undefined || style === "normal" || style === "check" ) {
+				if ( this.options.folded ) {
+					$listdivider.buttonMarkup();
+				} else {
+					$listdivider.wrapInner("<span class='ui-btn-text'></span>");
+				}
+
+				if ( this.options.listDividerLine ) {
+					expandSrc = "<span class='ui-divider-normal-line'></span>";
+					if ( this.options.folded ) {
+						$( expandSrc ).appendTo( $listdivider.children( ".ui-btn-inner" ) );
+					} else {
+						$( expandSrc ).appendTo( $listdivider);
+					}
+				}
+			}
+
+			$listdivider.bind( "vclick", function ( event, ui ) {
+			/* need to implement expand/collapse divider */
+			});
+		}
+	});
+
+	//auto self-init widgets
+	$( document ).bind( "pagecreate create", function ( e ) {
+		$( $.tizen.listdivider.prototype.options.initSelector, e.target ).listdivider();
+	});
+}( jQuery ) );
+
+//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
+} );
+//>>excludeEnd("jqmBuildExclude");