Best Python code snippet using fMBT_python
jquery.gestures.js
Source:jquery.gestures.js  
1(function(jQuery, $, window){2                                          /*jslint undef: true, browser: true, continue: true, eqeq: true, vars: true, forin: true, white: true, newcap: false, nomen: true, plusplus: true, maxerr: 50, indent: 4 */3/**4 * jGestures: a jQuery plugin for gesture events5 * Copyright 2010-2011 Neue Digitale / Razorfish GmbH6 * Copyright 2011-2012, Razorfish GmbH7 *8 * Licensed under the Apache License, Version 2.0 (the "License");9 * you may not use this file except in compliance with the License.10 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.011 * Unless required by applicable law or agreed to in writing, software12 * distributed under the License is distributed on an "AS IS" BASIS,13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.14 * See the License for the specific language governing permissions and15 * limitations under the License.16 *17 * @fileOverview18 * Razorfish GmbH javascript library: add touch events such as 'pinch',19 * 'rotate', 'swipe', 'tap' and 'orientationchange' on capable user agents.20 * For incapable devices there's a basic event substitution: a "tapone" event21 * can be triggered by "clicking", a "swipeone" by performing a swipe-ish22 * gesture using the mouse (buttondown - mousemove - buttonup).23 *24 * This is still a beta version, bugfixes and improvements appreciated.25 *26 * @author martin.krause@razorfish.de27 * @version 0.90-shake28 *29 * @requires30 * jQuery JavaScript Library v1.4.2 - http://jquery.com/31 *	Copyright 2010, John Resig32 *	Dual licensed under the MIT or GPL Version 2 licenses.33 *	http://jquery.org/license34 *35 * @example	jQuery('#swipe').bind('swipeone',eventHandler);36 *37 * Notification on native events:38 * On every native touchstart, touchend, gesturestart and gestureend-event,39 * jgestures triggers a corresponding custom event40 * ('jGestures.touchstart', 'jGestures.touchend;start', 'jGestures.touchend;processed',41 * 'jGestures.gesturestart', 'jGestures.gestureend;start', 'jGestures.gestureend;processed') on the event-element.42 * The  eventhandler's second argument represents the original touch event (yes: including all touchpoints).43 * Use this if you need very detailed control e.g. kinetic scrolling or implementing additional gestures.44 *45 * Every jGesture-eventhandler receives a custom object as second argument46 * containing the original event (originalEvent property) and processed47 * information (such as delta values and timesptamp).48 * Example:{49 *				type: eventtype e.g. "swipe","pinch",50 *				originalEvent: {DOM-Event},51 *				// default: just one entry on the delta-array - the first touchpoint52 *				// the first touchpoint is the reference point for every gesture,53 *				// because moving touchpoints in various directions would result in54 *				// a gesture.55 *				// delta and direction details are just provided for touch not for gesture / motion events56 *				delta : [57 *					{58 *						lastX:{Number} , // x-axis: relative to the last touchevent (e.g. touchmove!)59 *						lastY:{Number}, // y-axis: relative to the last touchevent (e.g. touchmove!)60 *						moved: {Number},  // distance: relative to the original touchpoint61 *						startX: {Number} , // relative to the original touchpoint62 *						startY: {Number} ,// relative to the original touchpoint63 *					} ],64 *				// based on the first touchpoint65 *				direction : { // relative to the last touchevent (e.g. touchmove!)66 *					vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)67 *					orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)68 *					lastX : {Number}, // -1,0,+1 || null (orientationchange) // relative to the last touchevent (e.g. touchmove!)69 *					lastY : {Number}, // -1,0,+1 || null (orientationchange)// relative to the last touchevent (e.g. touchmove!)70 *					startX: {Number} , // relative to the original touchpoint71 *					startY: {Number} ,// relative to the original touchpoint72 *				},73 *				rotation: {Number} || null, // gestureonly: amount of rotation relative to the current position NOT the original74 *				scale: {Number} || null, // gestureonly: amount of scaling relative to the current position NOT the original75 *				duration: {Number}, // ms: relative to the original touchpoint76 *				description : {String} // details as String: {TYPE *}:{TOUCHES 1|2|3|4}:{X-AXIS 'right'|'left'|'steady'}:{Y-AXIS 'down'|'up'|'steady'} e.g. "swipe:1:left:steady" relative to the last touchpoint77 *			};78 *79 * Available jGesture-events can be grouped into:80 *81 *82 * Device events:83 *	The jGesture-Events in this group are triggered by the device.84 *85 * @event 'orientationchange'86 *		The device is turned clockwise or counterclockwise. This event is triggered87 *		by the device and might use an internal gyroscope.88 *	obj.description:89 *		orientationchange:landscape:clockwise:-9090 *		orientationchange:portrait:default:091 *		orientationchange:landscape:counterclockwise|portrait:9092 *		orientationchange:portrait:upsidedown:18093 *94 *95 * Move events:96 *	The jGesture-Events in this group are triggered during the touch/gesture97 *	execution whenever a touchpoint changes.98 *	In contrast to touchend/gestureend-events which are triggered after99 *	the touch/gesture has completed.100 *101 * @event 'pinch'102 *		Is triggered during a pinch gesture (two fingers moving away from or103 *		towards each other).104 *	obj.description:105 *		pinch:-1:close106 *		pinch:+1:open107 *108 * @event 'rotate'109 *		Is triggered during a rotation gesture (two fingers rotating clockwise110 *		or counterclockwise).111 *	obj.description:112 *		rotate:-1:counterclockwise113 *		rotate:+1:+clockwise114 *115 * @event 'swipemove'116 *		Is triggered during a swipe move gesture (finger(s) being moved around117 *		the device, e.g. dragging)118 *	obj.description:119 *		swipemove:1:left:down120 *		swipemove:1:left:up121 *		swipemove:1:left:steady122 *		swipemove:1:right:down123 *		swipemove:1:right:up124 *		swipemove:1:right:steady125 *		swipemove:2:left:down126 *		swipemove:2:left:up127 *		swipemove:2:left:steady128 *		swipemove:2:right:down129 *		swipemove:2:right:up130 *		swipemove:2:right:steady131 *		swipemove:2:left:down132 *		swipemove:3:left:up133 *		swipemove:3:left:steady134 *		swipemove:3:right:down135 *		swipemove:3:right:up136 *		swipemove:3:right:steady137 *		swipemove:3:left:down138 *		swipemove:4:left:up139 *		swipemove:4:left:steady140 *		swipemove:4:right:down141 *		swipemove:4:right:up142 *		swipemove:4:right:steady143 *144 *145 * Toucheend events:146 *	The jGesture-Events in this group are triggered after the touch/gesture147 *	has completed.148 *	In contrast to touchmove-events which are triggered during the touch/gesture149 *	execution whenever a touchpoint changes.150 *151 * @event 'swipeone'152 *		Is triggered after a swipe move gesture with one touchpoint (one finger153 *		was moved around the device)154 *	obj.description:155 *		swipeone:1:left:down156 *		swipeone:1:left:up157 *		swipeone:1:left:steady158 *		swipeone:1:right:down159 *		swipeone:1:right:up160 *		swipeone:1:right:steady161 *162 * @event 'swipetwo'163 *		Is triggered after a swipe move gesture with two touchpoints (two fingers164 *		were moved around the device)165 *	obj.description:166 *		swipetwo:2:left:down167 *		swipetwo:2:left:up168 *		swipetwo:2:left:steady169 *		swipetwo:2:right:down170 *		swipetwo:2:right:up171 *		swipetwo:2:right:steady172 *173 * @event 'swipethree'174 *		Is triggered after a swipe move gesture with three touchpoints (three175 *		fingers were moved around the device)176 *	obj.description:177 *		swipethree:3:left:down178 *		swipethree:3:left:up179 *		swipethree:3:left:steady180 *		swipethree:3:right:down181 *		swipethree:3:right:up182 *		swipethree:3:right:steady183 *184 * @event 'swipefour'185 *		Is triggered after a swipe move gesture with four touchpoints (four186 *		fingers were moved around the device)187 *	obj.description:188 *		swipefour:4:left:down189 *		swipefour:4:left:up190 *		swipefour:4:left:steady191 *		swipefour:4:right:down192 *		swipefour:4:right:up193 *		swipefour:4:right:steady194 *195 *196 * @event 'swipeup'197 *		Is triggered after an  strict upwards swipe move gesture198 *	obj.description:199 *		swipe:1:steady:up200 *		swipe:2:steady:up201 *		swipe:3:steady:up202 *		swipe:4:steady:up203 *204 * @event 'swiperightup'205 *		Is triggered after a rightwards and upwards swipe move gesture206 *	obj.description:207 *		swipe:1:right:up208 *		swipe:2:right:up209 *		swipe:3:right:up210 *		swipe:4:right:up211 *212 * @event 'swiperight'213 *		Is triggered after a  strict rightwards swipe move gesture214 *	obj.description:215 *		swipe:1:right:steady216 *		swipe:2:right:steady217 *		swipe:3:right:steady218 *		swipe:4:right:steady219 *220 * @event 'swiperightdown'221 *		Is triggered after a rightwards and downwards swipe move gesture222 *	obj.description:223 *		swipe:1:right:down224 *		swipe:2:right:down225 *		swipe:3:right:down226 *		swipe:4:right:down227 *228 * @event 'swipedown'229 *		Is triggered after a  strict downwards swipe move gesture230 *	obj.description:231 *		swipe:1:steady:down232 *		swipe:2:steady:down233 *		swipe:3:steady:down234 *		swipe:4:steady:down235 *236 * @event 'swipeleftdown'237 *		Is triggered after a leftwards and downwards swipe move gesture238 *	obj.description:239 *		swipe:1:left:down240 *		swipe:2:left:down241 *		swipe:3:left:down242 *		swipe:4:left:down243 *244 * @event 'swipeleft'245 *		Is triggered after a strict leftwards swipe move gesture246 *	obj.description:247 *		swipe:1:left:steady248 *		swipe:2:left:steady249 *		swipe:3:left:steady250 *		swipe:4:left:steady251 *252 * @event 'swipeleftup'253 *		Is triggered after a leftwards and upwards swipe move gesture254 *	obj.description:255 *		swipe:1:left:up256 *		swipe:2:left:up257 *		swipe:3:left:up258 *		swipe:4:left:up259 *260 * @event 'tapone'261 *		Is triggered after a single (one finger) tap gesture262 *	obj.description:263 *		tapone264 *265 * @event 'taptwo'266 *		Is triggered after a double (two finger) tap gesture267 *	obj.description:268 *		taptwo269 * *270 * @event 'tapthree'271 *		Is triggered after a tripple (three finger) tap gesture272 *	obj.description:273 *		tapthree274 *275 *276 * Gestureend events:277 *	A gesture is an interpretation of different touchpoints.278 *	The jGesture-Events in this group are triggered when a gesture has finished279 *	and the touchpoints are removed from the device.280 *281 * @event 'pinchopen'282 *		Is triggered when a pinchopen gesture (two fingers moving away from each283 *		other) occured and the touchpoints (fingers) are removed the device.284 *	obj.description:285 *		pinch:+1:open286 *287 * @event 'pinchclose'288 *		Is triggered when a pinchclose gesture (two fingers moving towards each289 *		other) occured and the touchpoints (fingers) are removed the device.290 *	obj.description:291 *		pinch:-1:close292 *293 * @event 'rotatecw'294 *		Is triggered when a clockwise rotation gesture (two fingers rotating295 *		clockwise) occured and the touchpoints (fingers) are removed the device.296 *	obj.description:297 *		rotate:+1:+clockwise298 *299 * @event 'rotateccw'300 *		Is triggered when a counterclockwise rotation gesture (two fingers301 *		rotating counterclockwise) occured and the touchpoints (fingers) are302 *		removed the device.303 *	obj.description:304 *		rotate:-1:+counterclockwise305 *306 *307 * Motion events:308 *  A "motion event" is an interpretation of changes in space, e.g. a "shaking motion"309 *  consists of a specified number of acceleration changes in a given interval.310 * For understanding "directions", place your mobile device on a table with the bottom311 * (home button) close to you:312 *  - x-axis: horizontal left / right313 *  - y-axis: horizontal front / back (through the home button)314 *  - z-axis: vertical through your device315 *316 *  Note: Devicemotion / deviceorientation don't send custom event (such as: jGestures.touchstart).317 *  Note: Devicemotion should be bound on the "window-element" - because the whole device moves318 *319 * @event 'shake'320 *		Is triggered when a shaking motion is detected321 *	obj.description:322 *		shake:leftright:x-axisfrontback:y-axis:updown:z-axis323 *324 * @event 'shakefrontback'325 *		Is triggered when a shaking motion is detected and the gesture can be interpreted as a mainly front-back movement.326  *	obj.description:327 *		shakefrontback:shakefrontback:y-axis328 *329 * @event 'shakeleftright'330 *		Is triggered when a shaking motion is detected and the gesture can be interpreted as a mainly left-right movement.331 *		Additional major movements are mentioned in the obj.description.332 *	obj.description:333 *		shakeleftright:leftright:x-axis334 *335 * @event 'shakeupdown'336 *		Is triggered when a shaking motion is detected and the gesture can be interpreted as a mainly up-down movement.337 *		Additional major movements are mentioned in the obj.description.338 *	obj.description:339 *		shake:shakeupdown:updown:z-axis340 *341 * @example342 *		.bind( eventType, [ eventData ], handler(eventObject) )343 * jQuery('body').bind('tapone',function(){alert(arguments[1].description);})344 *345 */346 (function($) {347	/**348	* General thresholds.349	*/350	// @TODO: move to $...defaults351	// @TODO: shake to defaults freeze etc352	// change of x deg in y ms353	$.jGestures = {};354	$.jGestures.defaults = {};355	$.jGestures.defaults.thresholdShake =  {356		requiredShakes : 10,357		freezeShakes: 100,358		frontback : {359			sensitivity: 10360		 },361		leftright : {362			sensitivity: 10363		},364		updown : {365			sensitivity: 10366		}367	};368	$.jGestures.defaults.thresholdPinchopen = 0.05;369	$.jGestures.defaults.thresholdPinchmove = 0.05;370	$.jGestures.defaults.thresholdPinch = 0.05;371	$.jGestures.defaults.thresholdPinchclose = 0.05;372	$.jGestures.defaults.thresholdRotatecw = 5; //deg373	$.jGestures.defaults.thresholdRotateccw = 5; // deg374	// a tap becomes a swipe if x/y values changes are above this threshold375	$.jGestures.defaults.thresholdMove = 20;376	$.jGestures.defaults.thresholdSwipe = 100;377	// get capable user agents378	$.jGestures.data = {};379	$.jGestures.data.capableDevicesInUserAgentString = ['iPad','iPhone','iPod','Mobile Safari']; // basic functionality such as swipe, pinch, rotate, tap should work on every mobile safari, e.g. GalaxyTab380	$.jGestures.data.hasGestures = (function () { var _i; for(_i = 0; _i < $.jGestures.data.capableDevicesInUserAgentString.length; _i++ ) {  if (navigator.userAgent.indexOf($.jGestures.data.capableDevicesInUserAgentString[_i]) !== -1 ) {return true;} } return false; } )();381	$.hasGestures = $.jGestures.data.hasGestures;382	$.jGestures.events = {383		touchstart : 'jGestures.touchstart',384		touchendStart: 'jGestures.touchend;start',385		touchendProcessed: 'jGestures.touchend;processed',386		gesturestart: 'jGestures.gesturestart',387		gestureendStart: 'jGestures.gestureend;start',388		gestureendProcessed: 'jGestures.gestureend;processed'389	};390	jQuery391		.each({392			// "first domevent necessary"_"touch event+counter" : "exposed as"393			// event: orientationchange394			orientationchange_orientationchange01: "orientationchange",395			// event: gestures396			gestureend_pinchopen01: "pinchopen",397			gestureend_pinchclose01: "pinchclose",398			gestureend_rotatecw01 : 'rotatecw',399			gestureend_rotateccw01 : 'rotateccw',400			// move events401			gesturechange_pinch01: 'pinch',402			gesturechange_rotate01: 'rotate',403			touchstart_swipe13: 'swipemove',404			// event: touches405			touchstart_swipe01: "swipeone",406			touchstart_swipe02: "swipetwo",407			touchstart_swipe03: "swipethree",408			touchstart_swipe04: "swipefour",409			touchstart_swipe05: 'swipeup',410			touchstart_swipe06: 'swiperightup',411			touchstart_swipe07: 'swiperight',412			touchstart_swipe08: 'swiperightdown',413			touchstart_swipe09: 'swipedown',414			touchstart_swipe10: 'swipeleftdown',415			touchstart_swipe11: 'swipeleft',416			touchstart_swipe12: 'swipeleftup',417			touchstart_tap01: 'tapone',418			touchstart_tap02: 'taptwo',419			touchstart_tap03: 'tapthree',420			touchstart_tap04: 'tapfour',421			devicemotion_shake01: 'shake',422			devicemotion_shake02: 'shakefrontback',423			devicemotion_shake03: 'shakeleftright',424			devicemotion_shake04: 'shakeupdown'425		},426		/**427		* Add gesture events inside the jQuery.event.special namespace428		*/429		function( sInternal_, sPublicFN_ ) {430			// add as funciton to jQuery.event.special.sPublicFN_431			jQuery.event.special[ sPublicFN_ ] = {432				/**433				* When the first event handler is bound, jQuery executes the setup function.434				* This plugin just uses one eventhandler per element, regardless of the number of bound events.435				* All Events are stored internally as properties on the dom-element using the $.data api.436				* The setup-function adds the eventlistener, acting as a proxy function for the internal events.437				* $.data.ojQueryGestures[_sDOMEvent ('tap') ] = {Boolean}438				* @return {Void}439				*/440				setup: function () {441					// split the arguments to necessary controll arguements442					var _aSplit = sInternal_.split('_');443					var _sDOMEvent = _aSplit[0]; //444					// get the associated gesture event and strip the counter: necessary for distinguisihng similliar events such as tapone-tapfour445					var _sGestureEvent = _aSplit[1].slice(0,_aSplit[1].length-2);446					var _$element = jQuery(this);447					var _oDatajQueryGestures ;448					var oObj;449					// bind the event handler on the first $.bind() for a gestureend-event, set marker450					if (!_$element.data('ojQueryGestures') || !_$element.data('ojQueryGestures')[_sDOMEvent])  {451						// setup pseudo event452						_oDatajQueryGestures = _$element.data('ojQueryGestures') || {};453						oObj = {};454						// marker for:  domEvent being set on this element455						// e.g.: $.data.oGestureInternals['touchstart'] = true;456						// since they're grouped, i'm just marking the first one being added457						oObj[_sDOMEvent] = true;458						$.extend(true,_oDatajQueryGestures,oObj);459						_$element.data('ojQueryGestures' ,_oDatajQueryGestures);460						// add gesture events461						if($.hasGestures) {462							switch(_sGestureEvent) {463								// event: orientationchange464								case 'orientationchange':465									_$element.get(0).addEventListener('orientationchange', _onOrientationchange, false);466								break;467								// event:468								// - shake469								// - tilt470								case 'shake':471								case 'shakefrontback':472								case 'shakeleftright':473								case 'shakeupdown':474								case 'tilt':475									//$.hasGyroscope = true //!window.DeviceOrientationEvent;476									//_$element.get(0).addEventListener('devicemotion', _onDevicemotion, false);477									//_$element.get(0).addEventListener('deviceorientation', _onDeviceorientation, false);478									_$element.get(0).addEventListener('devicemotion', _onDevicemotion, false);479								break;480								// event:481								// - touchstart482								// - touchmove483								// - touchend484								case 'tap':485								case 'swipe':486								case 'swipeup':487								case 'swiperightup':488								case 'swiperight':489								case 'swiperightdown':490								case 'swipedown':491								case 'swipeleftdown':492								case 'swipeleft':493									_$element.get(0).addEventListener('touchstart', _onTouchstart, false);494								break;495								// event: gestureend496								case 'pinchopen':497								case 'pinchclose' :498								case 'rotatecw' :499								case 'rotateccw' :500									_$element.get(0).addEventListener('gesturestart', _onGesturestart, false);501									_$element.get(0).addEventListener('gestureend', _onGestureend, false);502								break;503								// event: gesturechange504								case 'pinch':505								case 'rotate':506									_$element.get(0).addEventListener('gesturestart', _onGesturestart, false);507									_$element.get(0).addEventListener('gesturechange', _onGesturechange, false);508								break;509							}510						}511						// create substitute for gesture events512						else {513							switch(_sGestureEvent) {514								// event substitutes:515								// - touchstart: mousedown516								// - touchmove: none517								// - touchend: mouseup518								case 'tap':519								case 'swipe':520									// _$element.get(0).addEventListener('mousedown', _onTouchstart, false);521									 _$element.bind('mousedown', _onTouchstart);522								break;523								// no substitution524								case 'orientationchange':525								case 'pinchopen':526								case 'pinchclose' :527								case 'rotatecw' :528								case 'rotateccw' :529								case 'pinch':530								case 'rotate':531								case 'shake':532								case 'tilt':533								break;534							}535						}536					}537					return false;538				},539				/**540				* For every $.bind(GESTURE) the add-function will be called.541				* Instead of binding an actual eventlister, the event is stored as $.data on the element.542				* The handler will be triggered using $.triggerHandler(GESTURE) if the internal543				* eventhandler (proxy being bound on setup()) detects a GESTURE event544				* @param {Object} event_ jQuery-Event-Object being passed by $.bind()545				* @return {Void}546				*/547				add : function(event_) {548					// add pseudo event: properties on $.data549					var _$element = jQuery(this);550					var _oDatajQueryGestures = _$element.data('ojQueryGestures');551//					_oDatajQueryGestures[event_.type] = { 'originalType' : event_.type , 'threshold' : event_.data.threshold, 'preventDefault' : event_.data.preventDefault } ;552					_oDatajQueryGestures[event_.type] = { 'originalType' : event_.type } ;553					return false;554				},555				/**556				* For every $.unbind(GESTURE) the remove-function will be called.557				* Instead of removing the actual eventlister, the event is removed from $.data on the element.558				* @param {Object} event_ jQuery-Event-Object being passed by $.bind()559				* @return {Void}560				*/561				remove : function(event_) {562					// remove pseudo event: properties on $.data563					var _$element = jQuery(this);564					var _oDatajQueryGestures = _$element.data('ojQueryGestures');565					_oDatajQueryGestures[event_.type] = false;566					_$element.data('ojQueryGestures' ,_oDatajQueryGestures );567					return false;568				},569				/**570				* The last $.unbind()-call on the domElement triggers the teardown function571				* removing the eventlistener572				* @return {Void}573				*/574				// @TODO: maybe rework teardown to work with event type?!575				teardown : function() {576					// split the arguments to necessary controll arguements577					var _aSplit = sInternal_.split('_');578					var _sDOMEvent = _aSplit[0]; //579					// get the associated gesture event and strip the counter: necessary for distinguisihng similliar events such as tapone-tapfour580					var _sGestureEvent = _aSplit[1].slice(0,_aSplit[1].length-2);581					var _$element = jQuery(this);582					var _oDatajQueryGestures;583					var oObj;584					// bind the event handler on the first $.bind() for a gestureend-event, set marker585					if (!_$element.data('ojQueryGestures') || !_$element.data('ojQueryGestures')[_sDOMEvent])  {586						// setup pseudo event587						_oDatajQueryGestures = _$element.data('ojQueryGestures') || {};588						oObj = {};589						// remove marker for:  domEvent being set on this element590						oObj[_sDOMEvent] = false;591						$.extend(true,_oDatajQueryGestures,oObj);592						_$element.data('ojQueryGestures' ,_oDatajQueryGestures);593						// remove gesture events594						if($.hasGestures) {595							switch(_sGestureEvent) {596								// event: orientationchange597								case 'orientationchange':598									_$element.get(0).removeEventListener('orientationchange', _onOrientationchange, false);599								break;600								case 'shake':601								case 'shakefrontback':602								case 'shakeleftright':603								case 'shakeupdown':604								case 'tilt':605									_$element.get(0).removeEventListener('devicemotion', _onDevicemotion, false);606								break;607								// event :608								// - touchstart609								// - touchmove610								// - touchend611								case 'tap':612								case 'swipe':613								case 'swipeup':614								case 'swiperightup':615								case 'swiperight':616								case 'swiperightdown':617								case 'swipedown':618								case 'swipeleftdown':619								case 'swipeleft':620								case 'swipeleftup':621									_$element.get(0).removeEventListener('touchstart', _onTouchstart, false);622									_$element.get(0).removeEventListener('touchmove', _onTouchmove, false);623									_$element.get(0).removeEventListener('touchend', _onTouchend, false);624								break;625								// event: gestureend626								case 'pinchopen':627								case 'pinchclose' :628								case 'rotatecw' :629								case 'rotateccw' :630									_$element.get(0).removeEventListener('gesturestart', _onGesturestart, false);631									_$element.get(0).removeEventListener('gestureend', _onGestureend, false);632								break;633								// event: gesturechange634								case 'pinch':635								case 'rotate':636									_$element.get(0).removeEventListener('gesturestart', _onGesturestart, false);637									_$element.get(0).removeEventListener('gesturechange', _onGesturechange, false);638								break;639							}640						}641						// remove substitute for gesture events642						else {643							switch(_sGestureEvent) {644								// event substitutes:645								// - touchstart: mousedown646								// - touchmove: none647								// - touchend: mouseup648								case 'tap':649								case 'swipe':650//									_$element.get(0).removeEventListener('mousedown', _onTouchstart, false);651//									_$element.get(0).removeEventListener('mousemove', _onTouchmove, false);652//									_$element.get(0).removeEventListener('mouseup', _onTouchend, false);653									_$element.unbind('mousedown', _onTouchstart);654									_$element.unbind('mousemove', _onTouchmove);655									_$element.unbind('mouseup', _onTouchend);656								break;657								// no substitution658								case 'orientationchange':659								case 'pinchopen':660								case 'pinchclose' :661								case 'rotatecw' :662								case 'rotateccw' :663								case 'pinch':664								case 'rotate':665								case 'shake':666								case 'tilt':667								break;668							}669						}670					}671				return false;672				}673			};674		});675	/**676	* Creates the object that ist passed as second argument to the $element.triggerHandler function.677	* This object contains detailed informations about the gesture event.678	* @param {Object} oOptions_  {type: {String}, touches: {String}, deltaY: {String},deltaX : {String}, startMove: {Object}, event:{DOM-Event}, timestamp:{String},vector: {Number}}679	* @example _createOptions (680	*				{681	*					type: 'swipemove',682	*					touches: '1',683	*					deltaY: _iDeltaY,684	*					deltaX : _iDeltaX,685	*					startMove: _oDatajQueryGestures.oStartTouch,686	*					event:event_,687	*					timestamp:_oEventData.timestamp,688	*					vector: -1689	*				}690	*			);691	* @returns {Object}692	*			{693	*				type: eventtype e.g. "swipe","pinch",694	*				originalEvent: {DOM-Event},695	*				// default: just one entry on the delta-array - the first touchpoint696	*				// the first touchpoint is the reference point for every gesture,697	*				// because moving touchpoints in various directions would result in698	*				// a gesture.699	*				// delta and direction details are just provided for touch not for gesture / motion events700	*				delta : [701	*					{702	*						lastX:{Number} , // x-axis: relative to the last touchevent (e.g. touchmove!)703	*						lastY:{Number}, // y-axis: relative to the last touchevent (e.g. touchmove!)704	*						moved: {Number},  // distance: relative to the original touchpoint705	*						startX: {Number} , // relative to the original touchpoint706	*						startY: {Number} ,// relative to the original touchpoint707	*					} ],708	*				// based on the first touchpoint709	*				direction : { // relative to the last touchevent (e.g. touchmove!)710	*					vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)711	*					orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)712	*					lastX : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)713	*					lastY : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)714	*					startX: {Number} , //-1,0,+1 relative to the original touchpoint715	*					startY: {Number} ,// -1,0,+1 relative to the original touchpoint716	*				},717	*				rotation: {Number} || null, // gestureonly: amount of rotation relative to the current position NOT the original718	*				scale: {Number} || null, // gestureonly: amount of scaling relative to the current position NOT the original719	*				duration: {Number}, // ms: relative to the original touchpoint720	*				description : {String} // details as String: {TYPE *}:{TOUCHES 1|2|3|4}:{X-AXIS 'right'|'left'|'steady'}:{Y-AXIS 'down'|'up'|'steady'} e.g. "swipe:1:left:steady" relative to the last touchpoint721	*			};722	*/723	function _createOptions(oOptions_) {724		// force properties725		oOptions_.startMove = (oOptions_.startMove) ? oOptions_.startMove : {startX: null,startY:null,timestamp:null}  ;726		var _iNow = new Date().getTime();727		var _oDirection;728		var _oDelta;729		// calculate touch differences730		if (oOptions_.touches) {731			// store delta values732			_oDelta = [733				{734					lastX: oOptions_.deltaX ,735					lastY: oOptions_.deltaY,736					moved: null,737					startX:  oOptions_.screenX - oOptions_.startMove.screenX ,738					startY: oOptions_.screenY - oOptions_.startMove.screenY739				}740			];741			_oDirection =  {742				vector: oOptions_.vector || null,743				orientation : window.orientation || null,744				lastX : ((_oDelta[0].lastX > 0) ? +1 : ( (_oDelta[0].lastX < 0) ? -1 : 0 ) ),745				lastY : ((_oDelta[0].lastY > 0) ? +1 : ( (_oDelta[0].lastY < 0) ? -1 : 0 ) ),746				startX : ((_oDelta[0].startX > 0) ? +1 : ( (_oDelta[0].startX < 0) ? -1 : 0 ) ),747				startY : ((_oDelta[0].startY > 0) ? +1 : ( (_oDelta[0].startY < 0) ? -1 : 0 ) )748			};749			// calculate distance traveled using the pythagorean theorem750			_oDelta[0].moved =  Math.sqrt(Math.pow(Math.abs(_oDelta[0].startX), 2) + Math.pow(Math.abs(_oDelta[0].startY), 2));751		}752		return {753			type: oOptions_.type || null,754			originalEvent: oOptions_.event || null,755			delta : _oDelta  || null,756			direction : _oDirection || { orientation : window.orientation || null, vector: oOptions_.vector || null},757			duration: (oOptions_.duration) ? oOptions_.duration : ( oOptions_.startMove.timestamp ) ? _iNow - oOptions_.timestamp : null,758			rotation: oOptions_.rotation || null,759			scale: oOptions_.scale || null,760			description : oOptions_.description || [761				oOptions_.type,762				':',763				oOptions_.touches,764				':',765				((_oDelta[0].lastX != 0) ? ((_oDelta[0].lastX > 0) ? 'right' : 'left') : 'steady'),766				':',767				((_oDelta[0].lastY != 0) ? ( (_oDelta[0].lastY > 0) ? 'down' : 'up') :'steady')768				].join('')769		};770	}771	/**772	* DOM-event handlers773	*/774	/**775	* Handler: orientationchange776	* Triggers the bound orientationchange handler on the window element777	* The "orientationchange" handler will receive an object with additional information778	* about the event.779	*  {780	*	direction : {781	*		orientation: {-90|0|90|180}782	*	},783	*	description : [784	*		'orientationchange:{landscape:clockwise:|portrait:default|landscape:counterclockwise|portrait:upsidedown}:{-90|0|90|180}' // e.g. 'orientation:landscape:clockwise:-90785	*	}786	* @param {DOM-Event} event_787	* @return {Void}788	*/789	function _onOrientationchange(event_) {790		// window.orientation: -90,0,90,180791		var _aDict = ['landscape:clockwise:','portrait:default:','landscape:counterclockwise:','portrait:upsidedown:'];792		$(window).triggerHandler('orientationchange',793			{794				direction : {orientation: window.orientation},795				description : [796					'orientationchange:',797					_aDict[( (window.orientation / 90) +1)],798					window.orientation799					].join('')800			});801	}802	/**803	* Handler: devicemotion804	* Calculates "motion events" such as shake, tilt, wiggle by observing "changes in space"805	* For understanding "directions", place your mobile device on a table with the bottom806	* (home button) close to you:807	*  - x-axis: horizontal left / right808	*  - y-axis: horizontal front / back (through the home button)809	*  - z-axis: vertical through your device810	* @param {DOM-Event} event_811	* @returns {Object}812	*			{813	*				type: eventtype e.g. "shake",814	*				originalEvent: {DOM-Event},815	*				// delta and direction details are just provided for touch not for gesture / motion events816	*				delta : null,817	*				direction :{818	*					vector: null,819	*					orientation: -90,0,90,180 || null (window.orienntation)820	*				}821	*				rotation: {Number} , //  amount of rotation relative to the current position NOT the original822	*				scale: {Number} , // amount of scaling relative to the current position NOT the original823	*				duration: {Number}, // ms: duration of the motion824	*				description : {String} // details as String: pinch:{'close'|'open'} e.g. "pinch:-1:close" ||  rotate:{'counterclockwise'|'clockwise'} e.g. "rotate:-1:counterclockwise"825	*			};826	* @param {DOM-Event} event_827	* @return {Void}828	*/829	function _onDevicemotion(event_) {830		var _sType;831		var _$element = jQuery(window);832		//var _bHasGyroscope = $.hasGyroscope;833		// skip custom notification: devicemotion is triggered every 0.05s regardlesse of any gesture834		// get options835		var _oDatajQueryGestures = _$element.data('ojQueryGestures');836		var _oThreshold = $.jGestures.defaults.thresholdShake;837		// get last position or set initital values838		var _oLastDevicePosition = _oDatajQueryGestures.oDeviceMotionLastDevicePosition || {839			accelerationIncludingGravity : {840				x: 0,841				y: 0,842				z: 0843			},844			shake : {845				eventCount: 0,846				intervalsPassed: 0,847				intervalsFreeze: 0848			},849			shakeleftright : {850				eventCount: 0,851				intervalsPassed: 0,852				intervalsFreeze: 0853			},854			shakefrontback : {855				eventCount: 0,856				intervalsPassed: 0,857				intervalsFreeze: 0858			},859			shakeupdown : {860				eventCount: 0,861				intervalsPassed: 0,862				intervalsFreeze: 0863			}864		};865		// cache current values866		var _oCurrentDevicePosition = {867			accelerationIncludingGravity : {868				x: event_.accelerationIncludingGravity.x,869				y: event_.accelerationIncludingGravity.y,870				z: event_.accelerationIncludingGravity.z871			},872			shake: {873				eventCount: _oLastDevicePosition.shake.eventCount,874				intervalsPassed: _oLastDevicePosition.shake.intervalsPassed,875				intervalsFreeze: _oLastDevicePosition.shake.intervalsFreeze876			 },877			 shakeleftright: {878				eventCount: _oLastDevicePosition.shakeleftright.eventCount,879				intervalsPassed: _oLastDevicePosition.shakeleftright.intervalsPassed,880				intervalsFreeze: _oLastDevicePosition.shakeleftright.intervalsFreeze881			 },882			 shakefrontback: {883				eventCount: _oLastDevicePosition.shakefrontback.eventCount,884				intervalsPassed: _oLastDevicePosition.shakefrontback.intervalsPassed,885				intervalsFreeze: _oLastDevicePosition.shakefrontback.intervalsFreeze886			 },887			 shakeupdown: {888				eventCount: _oLastDevicePosition.shakeupdown.eventCount,889				intervalsPassed: _oLastDevicePosition.shakeupdown.intervalsPassed,890				intervalsFreeze: _oLastDevicePosition.shakeupdown.intervalsFreeze891			 }892		};893		// options894		var _aType;895		var _aDescription;896		var _oObj;897		// trigger events for all bound pseudo events on this element898		for (_sType in _oDatajQueryGestures) {899			// get current pseudo event900			// trigger bound events on this element901			switch(_sType) {902				case 'shake':903				case 'shakeleftright':904				case 'shakefrontback':905				case 'shakeupdown':906					// options907					_aType = [];908					_aDescription = [];909					_aType.push(_sType);910					// freeze shake - prevent multiple shake events on one  shaking motion (user won't stop shaking immediately)911					if (++_oCurrentDevicePosition[_sType].intervalsFreeze > _oThreshold.freezeShakes && _oCurrentDevicePosition[_sType].intervalsFreeze < (2*_oThreshold.freezeShakes) ) { break;	}912					// set control values913					_oCurrentDevicePosition[_sType].intervalsFreeze  = 0;914					_oCurrentDevicePosition[_sType].intervalsPassed++;915					// check for shaking motions: massive acceleration changes in every direction916					if ( ( _sType === 'shake' ||_sType === 'shakeleftright' ) && ( _oCurrentDevicePosition.accelerationIncludingGravity.x > _oThreshold.leftright.sensitivity  || _oCurrentDevicePosition.accelerationIncludingGravity.x < (-1* _oThreshold.leftright.sensitivity) ) ) {917						_aType.push('leftright');918						_aType.push('x-axis');919					}920					if ( ( _sType === 'shake' ||_sType === 'shakefrontback' ) && (_oCurrentDevicePosition.accelerationIncludingGravity.y > _oThreshold.frontback.sensitivity  || _oCurrentDevicePosition.accelerationIncludingGravity.y < (-1 * _oThreshold.frontback.sensitivity) ) ) {921						_aType.push('frontback');922						_aType.push('y-axis');923					}924					if ( ( _sType === 'shake' ||_sType === 'shakeupdown' ) && ( _oCurrentDevicePosition.accelerationIncludingGravity.z+9.81 > _oThreshold.updown.sensitivity  || _oCurrentDevicePosition.accelerationIncludingGravity.z+9.81 < (-1 * _oThreshold.updown.sensitivity) ) ) {925						_aType.push('updown');926						_aType.push('z-axis');927					}928					// at least one successful shaking event929					if (_aType.length > 1) {930						// minimum number of shaking motions during  the defined "time" (messured by events - device event interval: 0.05s)931						if (++_oCurrentDevicePosition[_sType].eventCount == _oThreshold.requiredShakes && (_oCurrentDevicePosition[_sType].intervalsPassed) < _oThreshold.freezeShakes ) {932							// send event933							_$element.triggerHandler(_sType, _createOptions ({type: _sType, description: _aType.join(':'), event:event_,duration:_oCurrentDevicePosition[_sType].intervalsPassed*5 }) );934							// reset935							_oCurrentDevicePosition[_sType].eventCount = 0;936							_oCurrentDevicePosition[_sType].intervalsPassed = 0;937							// freeze shake938							_oCurrentDevicePosition[_sType].intervalsFreeze = _oThreshold.freezeShakes+1;939						}940						// too slow, reset941						else if (_oCurrentDevicePosition[_sType].eventCount == _oThreshold.requiredShakes && (_oCurrentDevicePosition[_sType].intervalsPassed) > _oThreshold.freezeShakes ) {942							_oCurrentDevicePosition[_sType].eventCount = 0 ;943							_oCurrentDevicePosition[_sType].intervalsPassed = 0;944						}945					}946				break;947			}948			// refresh pseudo events949			_oObj = {};950			_oObj.oDeviceMotionLastDevicePosition = _oCurrentDevicePosition;951			_$element.data('ojQueryGestures',$.extend(true,_oDatajQueryGestures,_oObj));952		}953	}954	/**955	* Handler: touchstart or mousedown956	* Setup pseudo-event by storing initial values such as :957	*	screenX : {Number}958	*	screenY : {Number}959	*	timestamp: {Number}960	*  on the pseudo gesture event and961	*  sets up additional eventlisteners for handling touchmove events.962	* @param {DOM-Event} event_963	* @return {Void}964	*/965	function _onTouchstart(event_) {966		// ignore bubbled handlers967		// if ( event_.currentTarget !== event_.target ) { return; }968		var _$element = jQuery(event_.currentTarget);969		// var _$element = jQuery(event_.target);970		// trigger custom notification971		_$element.triggerHandler($.jGestures.events.touchstart,event_);972		// set the necessary touch events973		if($.hasGestures) {974			event_.currentTarget.addEventListener('touchmove', _onTouchmove, false);975			event_.currentTarget.addEventListener('touchend', _onTouchend, false);976		}977		// event substitution978		else {979//			event_.currentTarget.addEventListener('mousemove', _onTouchmove, false);980//			event_.currentTarget.addEventListener('mouseup', _onTouchend, false);981			_$element.bind('mousemove', _onTouchmove);982			_$element.bind('mouseup', _onTouchend);983		}984		// get stored pseudo event985		var _oDatajQueryGestures = _$element.data('ojQueryGestures');986		// var _oEventData = _oDatajQueryGestures[_sType];987		var _eventBase = (event_.touches) ? event_.touches[0] : event_;988		// store current values for calculating relative values (changes between touchmoveevents)989		var _oObj = {};990		_oObj.oLastSwipemove = { screenX : _eventBase.screenX, screenY : _eventBase.screenY, timestamp:new Date().getTime()};991		_oObj.oStartTouch = { screenX : _eventBase.screenX, screenY : _eventBase.screenY, timestamp:new Date().getTime()};992		_$element.data('ojQueryGestures',$.extend(true,_oDatajQueryGestures,_oObj));993	}994	/**995	* Handler: touchmove or mousemove996	* Calculates the x/y changes since the last event,997	* compares it to $.jGestures.defaults.thresholdMove and triggers998	* an swipemove event if the distance exceed the999	* threshold.1000	* Custom-event argument object:1001	* {Object}1002	*			{1003	*				type: e.g. 'swipemove',1004	*				â: {DOM-Event},1005	*				// default: just one entry on the delta-array - the first touchpoint1006	*				// the first touchpoint is the reference point for every gesture,1007	*				// because moving touchpoints in various directions would result in1008	*				// a gesture.1009	*				// delta and direction details are just provided for touch not for gesture / motion events1010	*				delta : [1011	*					{1012	*						lastX:{Number} , // x-axis: relative to the last touchevent (e.g. touchmove!)1013	*						lastY:{Number}, // y-axis: relative to the last touchevent (e.g. touchmove!)1014	*						moved: {Number},  // distance: relative to the original touchpoint1015	*						startX: {Number} , // relative to the original touchpoint1016	*						startY: {Number} ,// relative to the original touchpoint1017	*					} ],1018	*				// based on the first touchpoint1019	*				direction : { // relative to the last touchevent (e.g. touchmove!)1020	*					vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)1021	*					orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)1022	*					lastX : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)1023	*					lastY : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)1024	*					startX: {Number} , //-1,0,+1 relative to the original touchpoint1025	*					startY: {Number} ,// -1,0,+1 relative to the original touchpoint1026	*				},1027	*				rotation: null, // gestureonly: amount of rotation relative to the current position NOT the original1028	*				scale: null, // gestureonly: amount of scaling relative to the current position NOT the original1029	*				duration: {Number}, // ms: relative to the original touchpoint1030	*				description : {String} // details as String: {TYPE *}:{TOUCHES 1|2|3|4}:{X-AXIS 'right'|'left'|'steady'}:{Y-AXIS 'down'|'up'|'steady'} e.g. "swipe:1:left:steady" relative to the last touchpoint1031	*			};1032	*1033	* @param {DOM-Event} event_1034	* @return {Void}1035	*/1036	function _onTouchmove(event_) {1037		var _$element = jQuery(event_.currentTarget);1038		// var _$element = jQuery(event_.target);1039		// get stored pseudo event1040		var _oDatajQueryGestures = _$element.data('ojQueryGestures');1041		var _bHasTouches = !!event_.touches;1042		var _iScreenX = (_bHasTouches) ? event_.changedTouches[0].screenX : event_.screenX;1043		var _iScreenY = (_bHasTouches) ? event_.changedTouches[0].screenY : event_.screenY;1044		//relative to the last event1045		var _oEventData = _oDatajQueryGestures.oLastSwipemove;1046		var _iDeltaX = _iScreenX - _oEventData.screenX   ;1047		var _iDeltaY = _iScreenY - _oEventData.screenY;1048		var _oDetails;1049			// there's a swipemove set (not the first occurance), trigger event1050		if (!!_oDatajQueryGestures.oLastSwipemove) {1051			// check1052			_oDetails = _createOptions({type: 'swipemove', touches: (_bHasTouches) ? event_.touches.length: '1', screenY: _iScreenY,screenX:_iScreenX ,deltaY: _iDeltaY,deltaX : _iDeltaX, startMove:_oEventData, event:event_, timestamp:_oEventData.timestamp});1053			_$element.triggerHandler(_oDetails.type,_oDetails);1054		}1055		// store the new values1056		var _oObj = {};1057		var _eventBase = (event_.touches) ? event_.touches[0] : event_;1058		_oObj.oLastSwipemove = { screenX : _eventBase.screenX, screenY : _eventBase.screenY, timestamp:new Date().getTime()};1059		_$element.data('ojQueryGestures',$.extend(true,_oDatajQueryGestures,_oObj));1060	}1061	/**1062	* Handler: touchend or mouseup1063	* Removes the additional handlers (move/end)1064	* Calculates the x/y changes since the touchstart event1065	* not in relation to the last move event.1066	* Triggers the1067	*	swipeone|swipetwo|swipethree|swipefour|1068	*	swipeup|swiperightup|swiperight|swiperightdown|swipedown|1069	*	swipeleftdown|swipeleft|swipeleftup|1070	*	tapone|taptwo|tapthree|tapfour1071	* event.1072	*		{Object}1073	*			{1074	*				type: eventtype e.g. "swipeone","swipeleftdown",1075	*				originalEvent: {DOM-Event},1076	*				// default: just one entry on the delta-array - the first touchpoint1077	*				// the first touchpoint is the reference point for every gesture,1078	*				// because moving touchpoints in various directions would result in1079	*				// a gesture.1080	*				// delta and direction details are just provided for touch not for gesture / motion events1081	*				delta : [1082	*					{1083	*						lastX:{Number} , // x-axis: relative to the last touchevent (e.g. touchmove!)1084	*						lastY:{Number}, // y-axis: relative to the last touchevent (e.g. touchmove!)1085	*						moved: {Number},  // distance: relative to the original touchpoint1086	*						startX: {Number} , // relative to the original touchpoint1087	*						startY: {Number} ,// relative to the original touchpoint1088	*					} ],1089	*				// based on the first touchpoint1090	*				direction : { // relative to the last touchevent (e.g. touchmove!)1091	*					vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)1092	*					orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)1093	*					lastX : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)1094	*					lastY : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)1095	*					startX: {Number} , //-1,0,+1 relative to the original touchpoint1096	*					startY: {Number} ,// -1,0,+1 relative to the original touchpoint1097	*				},1098	*				rotation: null,1099	*				scale: null ,1100	*				duration: {Number}, // ms: relative to the original touchpoint1101	*				description : {String} // details as String: {TYPE *}:{TOUCHES 1|2|3|4}:{X-AXIS 'right'|'left'|'steady'}:{Y-AXIS 'down'|'up'|'steady'} e.g. "swipe:1:left:steady" relative to the last touchpoint1102	*			};1103	* @param {DOM-Event} event_1104	* @return {Void}1105	*/1106	function _onTouchend(event_) {1107		// ignore bubbled handlers1108		// if ( event_.currentTarget !== event_.target ) { return; }1109		var _$element = jQuery(event_.currentTarget);1110		var _bHasTouches = !!event_.changedTouches;1111		var _iTouches = (_bHasTouches) ? event_.changedTouches.length : '1';1112		var _iScreenX = (_bHasTouches) ? event_.changedTouches[0].screenX : event_.screenX;1113		var _iScreenY = (_bHasTouches) ? event_.changedTouches[0].screenY : event_.screenY;1114		// trigger custom notification1115		_$element.triggerHandler($.jGestures.events.touchendStart,event_);1116		// var _$element = jQuery(event_.target);1117		// remove events1118		if($.hasGestures) {1119			event_.currentTarget.removeEventListener('touchmove', _onTouchmove, false);1120			event_.currentTarget.removeEventListener('touchend', _onTouchend, false);1121		}1122		// event substitution1123		else {1124//			event_.currentTarget.removeEventListener('mousemove', _onTouchmove, false);1125//			event_.currentTarget.removeEventListener('mouseup', _onTouchend, false);1126			_$element.unbind('mousemove', _onTouchmove);1127			_$element.unbind('mouseup', _onTouchend);1128		}1129		// get all bound pseudo events1130		var _oDatajQueryGestures = _$element.data('ojQueryGestures');1131		// if the current change on the x/y position is above the defined threshold for moving an element set the moved flag1132		// to distinguish between a moving gesture and a shaking finger trying to tap1133		var _bHasMoved = (1134			Math.abs(_oDatajQueryGestures.oStartTouch.screenX - _iScreenX) > $.jGestures.defaults.thresholdMove ||1135			Math.abs(_oDatajQueryGestures.oStartTouch.screenY - _iScreenY) > $.jGestures.defaults.thresholdMove1136		) ? true : false;1137		// if the current change on the x/y position is above the defined threshold for swiping set the moved flag1138		// to indicate we're dealing with a swipe gesture1139		var _bHasSwipeGesture = (1140			Math.abs(_oDatajQueryGestures.oStartTouch.screenX - _iScreenX) > $.jGestures.defaults.thresholdSwipe ||1141			Math.abs(_oDatajQueryGestures.oStartTouch.screenY - _iScreenY) > $.jGestures.defaults.thresholdSwipe1142		) ? true : false;1143		var _sType;1144		var _oEventData ;1145		var _oDelta;1146		// calculate distances in relation to the touchstart position not the last touchmove event!1147		var _iDeltaX;1148		var _iDeltaY;1149		var _oDetails;1150		var _aDict = ['zero','one','two','three','four'];1151		// swipe marker1152		var _bIsSwipe;1153		// trigger events for all bound pseudo events on this element1154		for (_sType in _oDatajQueryGestures) {1155			// get current pseudo event1156			_oEventData = _oDatajQueryGestures.oStartTouch;1157			_oDelta = {};1158			_iScreenX = (_bHasTouches) ? event_.changedTouches[0].screenX : event_.screenX;1159			_iScreenY = (_bHasTouches) ? event_.changedTouches[0].screenY : event_.screenY;1160			// calculate distances in relation to the touchstart position not the last touchmove event!1161			_iDeltaX = _iScreenX - _oEventData.screenX ;1162			_iDeltaY = _iScreenY - _oEventData.screenY;1163			_oDetails = _createOptions({type: 'swipe', touches: _iTouches, screenY: _iScreenY,screenX:_iScreenX ,deltaY: _iDeltaY,deltaX : _iDeltaX, startMove:_oEventData, event:event_, timestamp:  _oEventData.timestamp });1164			// swipe marker1165			_bIsSwipe = false;1166			// trigger bound events on this element1167			switch(_sType) {1168				case 'swipeone':1169					if( _bHasTouches === false && _iTouches == 1 && _bHasMoved === false){1170						// trigger tapone!1171						break;1172					}1173					if (_bHasTouches===false || ( _iTouches == 1  && _bHasMoved === true && _bHasSwipeGesture===true)) {1174						_bIsSwipe = true;1175						_oDetails.type = ['swipe',_aDict[_iTouches]].join('');1176						_$element.triggerHandler(_oDetails.type,_oDetails);1177					}1178				break;1179				case 'swipetwo':1180					if (( _bHasTouches && _iTouches== 2 && _bHasMoved === true && _bHasSwipeGesture===true)) {1181						_bIsSwipe = true;1182						_oDetails.type = ['swipe',_aDict[_iTouches]].join('');1183						_$element.triggerHandler(_oDetails.type,_oDetails);1184					}1185				break;1186				case 'swipethree':1187					if ( ( _bHasTouches && _iTouches == 3 && _bHasMoved === true && _bHasSwipeGesture===true)) {1188						_bIsSwipe = true;1189						_oDetails.type = ['swipe',_aDict[_iTouches]].join('');1190						_$element.triggerHandler(_oDetails.type,_oDetails);1191					}1192				break;1193				case 'swipefour':1194					if ( ( _bHasTouches && _iTouches == 4 && _bHasMoved === true && _bHasSwipeGesture===true)) {1195						_bIsSwipe = true;1196						_oDetails.type = ['swipe',_aDict[_iTouches]].join('');1197						_$element.triggerHandler(_oDetails.type,_oDetails);1198					}1199				break;1200				case 'swipeup':1201				case 'swiperightup':1202				case 'swiperight':1203				case 'swiperightdown':1204				case 'swipedown':1205				case 'swipeleftdown':1206				case 'swipeleft':1207				case 'swipeleftup':1208					if ( _bHasTouches && _bHasMoved === true && _bHasSwipeGesture===true) {1209						_bIsSwipe = true;1210						_oDetails.type = [1211									'swipe',1212								((_oDetails.delta[0].lastX != 0) ? ((_oDetails.delta[0].lastX > 0) ? 'right' : 'left') : ''),1213								((_oDetails.delta[0].lastY != 0) ? ((_oDetails.delta[0].lastY > 0) ? 'down' : 'up') :'')1214									].join('');1215						_$element.triggerHandler(_oDetails.type, _oDetails);1216					}1217				break;1218				case 'tapone':1219				case 'taptwo':1220				case 'tapthree':1221				case 'tapfour':1222					if (( /* _bHasTouches && */ _bHasMoved !== true && _bIsSwipe !==true) && (_aDict[_iTouches] ==_sType.slice(3)) ) {1223						_oDetails.description = ['tap',_aDict[_iTouches]].join('');1224						_oDetails.type = ['tap',_aDict[_iTouches]].join('');1225						_$element.triggerHandler(_oDetails.type,_oDetails);1226						}1227					break;1228			}1229			// refresh pseudo events1230			var _oObj = {};1231//			_oObj[_sType] = false;1232//			_oObj.hasTouchmoved = false;1233			_$element.data('ojQueryGestures',$.extend(true,_oDatajQueryGestures,_oObj));1234			_$element.data('ojQueryGestures',$.extend(true,_oDatajQueryGestures,_oObj));1235		}1236		_$element.triggerHandler($.jGestures.events.touchendProcessed,event_);1237	}1238	/**1239	* Handler: gesturestart1240	* Setup pseudo-event by storing initial values such as :1241	*	timestamp: {Number}1242	*  on the pseudo gesture event1243	* Since the gesture-event doesn't supply event.touches no tuchpoints will be calculated1244	* @param {DOM-Event} event_1245	* @return {Void}1246	*/1247	function _onGesturestart(event_) {1248		// ignore bubbled handlers1249		// if ( event_.currentTarget !== event_.target ) { return; }1250		var _$element = jQuery(event_.currentTarget);1251		// var _$element = jQuery(event_.target);1252		// trigger custom notification1253		_$element.triggerHandler($.jGestures.events.gesturestart,event_);1254		// get stored pseudo event1255		var _oDatajQueryGestures = _$element.data('ojQueryGestures');1256		// var _oEventData = _oDatajQueryGestures[_sType];1257		// store current values for calculating relative values (changes between touchmoveevents)1258		var _oObj = {};1259		_oObj.oStartTouch = {timestamp:new Date().getTime()};1260		_$element.data('ojQueryGestures',$.extend(true,_oDatajQueryGestures,_oObj));1261	}1262	/**1263	* Handler: gesturechange1264	* Read the event_.scale / event_.rotate values,1265	* an triggers a pinch|rotate event if necessary.1266	* Since the gesture-event doesn't supply event.touches no tuchpoints will be calculated1267	* @returns {Object}1268	*			{1269	*				type: eventtype e.g. "pinch","rotate",1270	*				originalEvent: {DOM-Event},1271	*				// delta and direction details are just provided for touch not for gesture / motion events1272	*				delta : null,1273	*				direction : {1274	*					vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)1275	*					 orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)1276	*				 },1277	*				rotation: {Number} , //  amount of rotation relative to the current position NOT the original1278	*				scale: {Number} , // amount of scaling relative to the current position NOT the original1279	*				duration: {Number}, // ms: relative to the original touchpoint1280	*				description : {String} // details as String: pinch:{'close'|'open'} e.g. "pinch:-1:close" ||  rotate:{'counterclockwise'|'clockwise'} e.g. "rotate:-1:counterclockwise"1281	*			};1282	* @param {DOM-Event} event_1283	* @return {Void}1284	*/1285	function _onGesturechange(event_) {1286		// ignore bubbled handlers1287		// if ( event_.currentTarget !== event_.target ) { return; }1288		var _$element = jQuery(event_.currentTarget);1289		// var _$element = jQuery(event_.target);1290		var _iDelta,_iDirection,_sDesc,_oDetails;1291		// get all pseudo events1292		var _oDatajQueryGestures = _$element.data('ojQueryGestures');1293		// trigger events for all bound pseudo events on this element1294		var _sType;1295		for (_sType in _oDatajQueryGestures) {1296			// trigger a specific bound event1297			switch(_sType) {1298				case 'pinch':1299					_iDelta = event_.scale;1300					if ( ( ( _iDelta < 1 ) && (_iDelta % 1) < (1 - $.jGestures.defaults.thresholdPinchclose) ) || ( ( _iDelta > 1 ) && (_iDelta % 1) > ($.jGestures.defaults.thresholdPinchopen) ) ) {1301						_iDirection = (_iDelta < 1 ) ? -1 : +1 ;1302						_oDetails = _createOptions({type: 'pinch', scale: _iDelta, touches: null,startMove:_oDatajQueryGestures.oStartTouch, event:event_, timestamp: _oDatajQueryGestures.oStartTouch.timestamp, vector:_iDirection, description: ['pinch:',_iDirection,':' , ( (_iDelta < 1 ) ? 'close' : 'open' )].join('') });1303						_$element.triggerHandler(_oDetails.type, _oDetails);1304					}1305				break;1306				case 'rotate':1307					_iDelta = event_.rotation;1308					if ( ( ( _iDelta < 1 ) &&  ( -1*(_iDelta) > $.jGestures.defaults.thresholdRotateccw ) ) || ( ( _iDelta > 1 ) && (_iDelta  > $.jGestures.defaults.thresholdRotatecw) ) ) {1309						_iDirection = (_iDelta < 1 ) ? -1 : +1 ;1310						_oDetails = _createOptions({type: 'rotate', rotation: _iDelta, touches: null, startMove:_oDatajQueryGestures.oStartTouch, event:event_, timestamp: _oDatajQueryGestures.oStartTouch.timestamp, vector:_iDirection, description: ['rotate:',_iDirection,':' , ( (_iDelta < 1 ) ? 'counterclockwise' : 'clockwise' )].join('') });1311						_$element.triggerHandler(_oDetails.type, _oDetails);1312					}1313				break;1314			}1315		}1316	}1317	/**1318	* Handler: gestureend1319	* Read the event_.scale / event_.rotate values,1320	* compares it to $.jGestures.defaults.threshold* and triggers1321	* a pinchclose|pinchclose|rotatecw|rotateccw event if the distance exceed the1322	* Since the gesture-event doesn't supply event.touches no tuchpoints will be calculated1323	* * Custom-event argument object:1324	* @returns {Object}1325	*			{1326	*				type: eventtype e.g. "pinchclose","pinchopen", "rotatecw", "rotateccw",1327	*				originalEvent: {DOM-Event},1328	*				// delta and direction details are just provided for touch not for gesture / motion events1329	*				delta : null,1330	*				// based on the first touchpoint1331	*				direction : {1332	*					vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)1333	*					orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)1334	*				},1335	*				rotation: {Number} , //  amount of rotation relative to the current position NOT the original1336	*				scale: {Number} , // amount of scaling relative to the current position NOT the original1337	*				duration: {Number}, // ms: relative to the original touchpoint1338	*				description : {String} // details as String: pinch:{'close'|'open'} e.g. "pinch:-1:close" ||  rotate:{'counterclockwise'|'clockwise'} e.g. "rotate:-1:counterclockwise"1339	*			};1340	* @param {DOM-Event} event_1341	* @return {Void}1342	*/1343	function _onGestureend(event_) {1344		// ignore bubbled handlers1345		// if ( event_.currentTarget !== event_.target ) { return; }1346		var _$element = jQuery(event_.currentTarget);1347		// var _$element = jQuery(event_.target);1348		// trigger custom notification1349		_$element.triggerHandler($.jGestures.events.gestureendStart,event_);1350		var _iDelta;1351		var _oDatajQueryGestures = _$element.data('ojQueryGestures');1352		// trigger handler for every bound event1353		var _sType;1354		for (_sType in _oDatajQueryGestures) {1355			switch(_sType) {1356				case 'pinchclose':1357					_iDelta = event_.scale;1358					if (( _iDelta < 1 ) && (_iDelta % 1) < (1 - $.jGestures.defaults.thresholdPinchclose)) {1359						_$element.triggerHandler('pinchclose', _createOptions ({type: 'pinchclose', scale:_iDelta, vector: -1, touches: null, startMove: _oDatajQueryGestures.oStartTouch, event:event_, timestamp:_oDatajQueryGestures.oStartTouch.timestamp,description: 'pinch:-1:close' }) );1360					}1361				break;1362				case 'pinchopen':1363					_iDelta = event_.scale;1364					if ( ( _iDelta > 1 ) && (_iDelta % 1) > ($.jGestures.defaults.thresholdPinchopen) ) {1365						_$element.triggerHandler('pinchopen', _createOptions ({type: 'pinchopen', scale:_iDelta, vector: +1, touches: null, startMove: _oDatajQueryGestures.oStartTouch, event:event_, timestamp:_oDatajQueryGestures.oStartTouch.timestamp,description: 'pinch:+1:open'}) );1366					}1367				break;1368				case 'rotatecw':1369					_iDelta = event_.rotation;1370					if ( ( _iDelta > 1 ) && (_iDelta  > $.jGestures.defaults.thresholdRotatecw) ) {1371						_$element.triggerHandler('rotatecw', _createOptions ({type: 'rotatecw', rotation:_iDelta, vector: +1, touches: null, startMove: _oDatajQueryGestures.oStartTouch, event:event_, timestamp:_oDatajQueryGestures.oStartTouch.timestamp,description: 'rotate:+1:clockwise'}) );1372					}1373				break;1374				case 'rotateccw':1375					_iDelta = event_.rotation;1376					if ( ( _iDelta < 1 ) &&  ( -1*(_iDelta) > $.jGestures.defaults.thresholdRotateccw ) ) {1377							_$element.triggerHandler('rotateccw', _createOptions ({type: 'rotateccw', rotation:_iDelta, vector: -1, touches: null, startMove: _oDatajQueryGestures.oStartTouch, event:event_, timestamp:_oDatajQueryGestures.oStartTouch.timestamp,description: 'rotate:-1:counterclockwise'}) );1378						}1379				break;1380				}1381			}1382			_$element.triggerHandler($.jGestures.events.gestureendProcessed,event_);1383		}1384	}1385)(jQuery);...mobile.js
Source:mobile.js  
1/*jslint undef: true, browser: true, continue: true, eqeq: true, vars: true, forin: true, white: true, newcap: false, nomen: true, plusplus: true, maxerr: 50, indent: 4 */2/**3 * jGestures: a jQuery plugin for gesture events4 * Copyright 2010-2011 Neue Digitale / Razorfish GmbH5 * Copyright 2011-2012, Razorfish GmbH6 *7 * Licensed under the Apache License, Version 2.0 (the "License");8 * you may not use this file except in compliance with the License.9 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.010 * Unless required by applicable law or agreed to in writing, software11 * distributed under the License is distributed on an "AS IS" BASIS,12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13 * See the License for the specific language governing permissions and14 * limitations under the License.15 *16 * @fileOverview17 * Razorfish GmbH javascript library: add touch events such as 'pinch',18 * 'rotate', 'swipe', 'tap' and 'orientationchange' on capable user agents.19 * For incapable devices there's a basic event substitution: a "tapone" event20 * can be triggered by "clicking", a "swipeone" by performing a swipe-ish21 * gesture using the mouse (buttondown - mousemove - buttonup).22 *23 * This is still a beta version, bugfixes and improvements appreciated.24 *25 * @author martin.krause@razorfish.de26 * @version 0.90-shake27 *28 * @requires29 * jQuery JavaScript Library v1.4.2 - http://jquery.com/30 *	Copyright 2010, John Resig31 *	Dual licensed under the MIT or GPL Version 2 licenses.32 *	http://jquery.org/license33 *34 * @example	jQuery('#swipe').bind('swipeone',eventHandler);35 *36 * Notification on native events:37 * On every native touchstart, touchend, gesturestart and gestureend-event,38 * jgestures triggers a corresponding custom event39 * ('jGestures.touchstart', 'jGestures.touchend;start', 'jGestures.touchend;processed',40 * 'jGestures.gesturestart', 'jGestures.gestureend;start', 'jGestures.gestureend;processed') on the event-element.41 * The  eventhandler's second argument represents the original touch event (yes: including all touchpoints).42 * Use this if you need very detailed control e.g. kinetic scrolling or implementing additional gestures.43 *44 * Every jGesture-eventhandler receives a custom object as second argument45 * containing the original event (originalEvent property) and processed46 * information (such as delta values and timesptamp).47 * Example:{48 *				type: eventtype e.g. "swipe","pinch",49 *				originalEvent: {DOM-Event},50 *				// default: just one entry on the delta-array - the first touchpoint51 *				// the first touchpoint is the reference point for every gesture,52 *				// because moving touchpoints in various directions would result in53 *				// a gesture.54 *				// delta and direction details are just provided for touch not for gesture / motion events55 *				delta : [56 *					{57 *						lastX:{Number} , // x-axis: relative to the last touchevent (e.g. touchmove!)58 *						lastY:{Number}, // y-axis: relative to the last touchevent (e.g. touchmove!)59 *						moved: {Number},  // distance: relative to the original touchpoint60 *						startX: {Number} , // relative to the original touchpoint61 *						startY: {Number} ,// relative to the original touchpoint62 *					} ],63 *				// based on the first touchpoint64 *				direction : { // relative to the last touchevent (e.g. touchmove!)65 *					vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)66 *					orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)67 *					lastX : {Number}, // -1,0,+1 || null (orientationchange) // relative to the last touchevent (e.g. touchmove!)68 *					lastY : {Number}, // -1,0,+1 || null (orientationchange)// relative to the last touchevent (e.g. touchmove!)69 *					startX: {Number} , // relative to the original touchpoint70 *					startY: {Number} ,// relative to the original touchpoint71 *				},72 *				rotation: {Number} || null, // gestureonly: amount of rotation relative to the current position NOT the original73 *				scale: {Number} || null, // gestureonly: amount of scaling relative to the current position NOT the original74 *				duration: {Number}, // ms: relative to the original touchpoint75 *				description : {String} // details as String: {TYPE *}:{TOUCHES 1|2|3|4}:{X-AXIS 'right'|'left'|'steady'}:{Y-AXIS 'down'|'up'|'steady'} e.g. "swipe:1:left:steady" relative to the last touchpoint76 *			};77 *78 * Available jGesture-events can be grouped into:79 *80 *81 * Device events:82 *	The jGesture-Events in this group are triggered by the device.83 *84 * @event 'orientationchange'85 *		The device is turned clockwise or counterclockwise. This event is triggered86 *		by the device and might use an internal gyroscope.87 *	obj.description:88 *		orientationchange:landscape:clockwise:-9089 *		orientationchange:portrait:default:090 *		orientationchange:landscape:counterclockwise|portrait:9091 *		orientationchange:portrait:upsidedown:18092 *93 *94 * Move events:95 *	The jGesture-Events in this group are triggered during the touch/gesture96 *	execution whenever a touchpoint changes.97 *	In contrast to touchend/gestureend-events which are triggered after98 *	the touch/gesture has completed.99 *100 * @event 'pinch'101 *		Is triggered during a pinch gesture (two fingers moving away from or102 *		towards each other).103 *	obj.description:104 *		pinch:-1:close105 *		pinch:+1:open106 *107 * @event 'rotate'108 *		Is triggered during a rotation gesture (two fingers rotating clockwise109 *		or counterclockwise).110 *	obj.description:111 *		rotate:-1:counterclockwise112 *		rotate:+1:+clockwise113 *114 * @event 'swipemove'115 *		Is triggered during a swipe move gesture (finger(s) being moved around116 *		the device, e.g. dragging)117 *	obj.description:118 *		swipemove:1:left:down119 *		swipemove:1:left:up120 *		swipemove:1:left:steady121 *		swipemove:1:right:down122 *		swipemove:1:right:up123 *		swipemove:1:right:steady124 *		swipemove:2:left:down125 *		swipemove:2:left:up126 *		swipemove:2:left:steady127 *		swipemove:2:right:down128 *		swipemove:2:right:up129 *		swipemove:2:right:steady130 *		swipemove:2:left:down131 *		swipemove:3:left:up132 *		swipemove:3:left:steady133 *		swipemove:3:right:down134 *		swipemove:3:right:up135 *		swipemove:3:right:steady136 *		swipemove:3:left:down137 *		swipemove:4:left:up138 *		swipemove:4:left:steady139 *		swipemove:4:right:down140 *		swipemove:4:right:up141 *		swipemove:4:right:steady142 *143 *144 * Toucheend events:145 *	The jGesture-Events in this group are triggered after the touch/gesture146 *	has completed.147 *	In contrast to touchmove-events which are triggered during the touch/gesture148 *	execution whenever a touchpoint changes.149 *150 * @event 'swipeone'151 *		Is triggered after a swipe move gesture with one touchpoint (one finger152 *		was moved around the device)153 *	obj.description:154 *		swipeone:1:left:down155 *		swipeone:1:left:up156 *		swipeone:1:left:steady157 *		swipeone:1:right:down158 *		swipeone:1:right:up159 *		swipeone:1:right:steady160 *161 * @event 'swipetwo'162 *		Is triggered after a swipe move gesture with two touchpoints (two fingers163 *		were moved around the device)164 *	obj.description:165 *		swipetwo:2:left:down166 *		swipetwo:2:left:up167 *		swipetwo:2:left:steady168 *		swipetwo:2:right:down169 *		swipetwo:2:right:up170 *		swipetwo:2:right:steady171 *172 * @event 'swipethree'173 *		Is triggered after a swipe move gesture with three touchpoints (three174 *		fingers were moved around the device)175 *	obj.description:176 *		swipethree:3:left:down177 *		swipethree:3:left:up178 *		swipethree:3:left:steady179 *		swipethree:3:right:down180 *		swipethree:3:right:up181 *		swipethree:3:right:steady182 *183 * @event 'swipefour'184 *		Is triggered after a swipe move gesture with four touchpoints (four185 *		fingers were moved around the device)186 *	obj.description:187 *		swipefour:4:left:down188 *		swipefour:4:left:up189 *		swipefour:4:left:steady190 *		swipefour:4:right:down191 *		swipefour:4:right:up192 *		swipefour:4:right:steady193 *194 *195 * @event 'swipeup'196 *		Is triggered after an  strict upwards swipe move gesture197 *	obj.description:198 *		swipe:1:steady:up199 *		swipe:2:steady:up200 *		swipe:3:steady:up201 *		swipe:4:steady:up202 *203 * @event 'swiperightup'204 *		Is triggered after a rightwards and upwards swipe move gesture205 *	obj.description:206 *		swipe:1:right:up207 *		swipe:2:right:up208 *		swipe:3:right:up209 *		swipe:4:right:up210 *211 * @event 'swiperight'212 *		Is triggered after a  strict rightwards swipe move gesture213 *	obj.description:214 *		swipe:1:right:steady215 *		swipe:2:right:steady216 *		swipe:3:right:steady217 *		swipe:4:right:steady218 *219 * @event 'swiperightdown'220 *		Is triggered after a rightwards and downwards swipe move gesture221 *	obj.description:222 *		swipe:1:right:down223 *		swipe:2:right:down224 *		swipe:3:right:down225 *		swipe:4:right:down226 *227 * @event 'swipedown'228 *		Is triggered after a  strict downwards swipe move gesture229 *	obj.description:230 *		swipe:1:steady:down231 *		swipe:2:steady:down232 *		swipe:3:steady:down233 *		swipe:4:steady:down234 *235 * @event 'swipeleftdown'236 *		Is triggered after a leftwards and downwards swipe move gesture237 *	obj.description:238 *		swipe:1:left:down239 *		swipe:2:left:down240 *		swipe:3:left:down241 *		swipe:4:left:down242 *243 * @event 'swipeleft'244 *		Is triggered after a strict leftwards swipe move gesture245 *	obj.description:246 *		swipe:1:left:steady247 *		swipe:2:left:steady248 *		swipe:3:left:steady249 *		swipe:4:left:steady250 *251 * @event 'swipeleftup'252 *		Is triggered after a leftwards and upwards swipe move gesture253 *	obj.description:254 *		swipe:1:left:up255 *		swipe:2:left:up256 *		swipe:3:left:up257 *		swipe:4:left:up258 *259 * @event 'tapone'260 *		Is triggered after a single (one finger) tap gesture261 *	obj.description:262 *		tapone263 *264 * @event 'taptwo'265 *		Is triggered after a double (two finger) tap gesture266 *	obj.description:267 *		taptwo268 * *269 * @event 'tapthree'270 *		Is triggered after a tripple (three finger) tap gesture271 *	obj.description:272 *		tapthree273 *274 *275 * Gestureend events:276 *	A gesture is an interpretation of different touchpoints.277 *	The jGesture-Events in this group are triggered when a gesture has finished278 *	and the touchpoints are removed from the device.279 *280 * @event 'pinchopen'281 *		Is triggered when a pinchopen gesture (two fingers moving away from each282 *		other) occured and the touchpoints (fingers) are removed the device.283 *	obj.description:284 *		pinch:+1:open285 *286 * @event 'pinchclose'287 *		Is triggered when a pinchclose gesture (two fingers moving towards each288 *		other) occured and the touchpoints (fingers) are removed the device.289 *	obj.description:290 *		pinch:-1:close291 *292 * @event 'rotatecw'293 *		Is triggered when a clockwise rotation gesture (two fingers rotating294 *		clockwise) occured and the touchpoints (fingers) are removed the device.295 *	obj.description:296 *		rotate:+1:+clockwise297 *298 * @event 'rotateccw'299 *		Is triggered when a counterclockwise rotation gesture (two fingers300 *		rotating counterclockwise) occured and the touchpoints (fingers) are301 *		removed the device.302 *	obj.description:303 *		rotate:-1:+counterclockwise304 *305 *306 * Motion events:307 *  A "motion event" is an interpretation of changes in space, e.g. a "shaking motion"308 *  consists of a specified number of acceleration changes in a given interval.309 * For understanding "directions", place your mobile device on a table with the bottom310 * (home button) close to you:311 *  - x-axis: horizontal left / right312 *  - y-axis: horizontal front / back (through the home button)313 *  - z-axis: vertical through your device314 *315 *  Note: Devicemotion / deviceorientation don't send custom event (such as: jGestures.touchstart).316 *  Note: Devicemotion should be bound on the "window-element" - because the whole device moves317 *318 * @event 'shake'319 *		Is triggered when a shaking motion is detected320 *	obj.description:321 *		shake:leftright:x-axisfrontback:y-axis:updown:z-axis322 *323 * @event 'shakefrontback'324 *		Is triggered when a shaking motion is detected and the gesture can be interpreted as a mainly front-back movement.325  *	obj.description:326 *		shakefrontback:shakefrontback:y-axis327 *328 * @event 'shakeleftright'329 *		Is triggered when a shaking motion is detected and the gesture can be interpreted as a mainly left-right movement.330 *		Additional major movements are mentioned in the obj.description.331 *	obj.description:332 *		shakeleftright:leftright:x-axis333 *334 * @event 'shakeupdown'335 *		Is triggered when a shaking motion is detected and the gesture can be interpreted as a mainly up-down movement.336 *		Additional major movements are mentioned in the obj.description.337 *	obj.description:338 *		shake:shakeupdown:updown:z-axis339 *340 * @example341 *		.bind( eventType, [ eventData ], handler(eventObject) )342 * jQuery('body').bind('tapone',function(){alert(arguments[1].description);})343 *344 */345 (function($) {346	/**347	* General thresholds.348	*/349	// @TODO: move to $...defaults350	// @TODO: shake to defaults freeze etc351	// change of x deg in y ms352	$.jGestures = {};353	$.jGestures.defaults = {};354	$.jGestures.defaults.thresholdShake =  {355		requiredShakes : 10,356		freezeShakes: 100,357		frontback : {358			sensitivity: 10359		 },360		leftright : {361			sensitivity: 10362		},363		updown : {364			sensitivity: 10365		}366	};367	$.jGestures.defaults.thresholdPinchopen = 0.05;368	$.jGestures.defaults.thresholdPinchmove = 0.05;369	$.jGestures.defaults.thresholdPinch = 0.05;370	$.jGestures.defaults.thresholdPinchclose = 0.05;371	$.jGestures.defaults.thresholdRotatecw = 5; //deg372	$.jGestures.defaults.thresholdRotateccw = 5; // deg373	// a tap becomes a swipe if x/y values changes are above this threshold374	$.jGestures.defaults.thresholdMove = 20;375	$.jGestures.defaults.thresholdSwipe = 100;376	// get capable user agents377	$.jGestures.data = {};378	$.jGestures.data.capableDevicesInUserAgentString = ['iPad','iPhone','iPod','Mobile Safari']; // basic functionality such as swipe, pinch, rotate, tap should work on every mobile safari, e.g. GalaxyTab379	$.jGestures.data.hasGestures = (function () { var _i; for(_i = 0; _i < $.jGestures.data.capableDevicesInUserAgentString.length; _i++ ) {  if (navigator.userAgent.indexOf($.jGestures.data.capableDevicesInUserAgentString[_i]) !== -1 ) {return true;} } return false; } )();380	$.hasGestures = $.jGestures.data.hasGestures;381	$.jGestures.events = {382		touchstart : 'jGestures.touchstart',383		touchendStart: 'jGestures.touchend;start',384		touchendProcessed: 'jGestures.touchend;processed',385		gesturestart: 'jGestures.gesturestart',386		gestureendStart: 'jGestures.gestureend;start',387		gestureendProcessed: 'jGestures.gestureend;processed'388	};389	jQuery390		.each({391			// "first domevent necessary"_"touch event+counter" : "exposed as"392			// event: orientationchange393			orientationchange_orientationchange01: "orientationchange",394			// event: gestures395			gestureend_pinchopen01: "pinchopen",396			gestureend_pinchclose01: "pinchclose",397			gestureend_rotatecw01 : 'rotatecw',398			gestureend_rotateccw01 : 'rotateccw',399			// move events400			gesturechange_pinch01: 'pinch',401			gesturechange_rotate01: 'rotate',402			touchstart_swipe13: 'swipemove',403			// event: touches404			touchstart_swipe01: "swipeone",405			touchstart_swipe02: "swipetwo",406			touchstart_swipe03: "swipethree",407			touchstart_swipe04: "swipefour",408			touchstart_swipe05: 'swipeup',409			touchstart_swipe06: 'swiperightup',410			touchstart_swipe07: 'swiperight',411			touchstart_swipe08: 'swiperightdown',412			touchstart_swipe09: 'swipedown',413			touchstart_swipe10: 'swipeleftdown',414			touchstart_swipe11: 'swipeleft',415			touchstart_swipe12: 'swipeleftup',416			touchstart_tap01: 'tapone',417			touchstart_tap02: 'taptwo',418			touchstart_tap03: 'tapthree',419			touchstart_tap04: 'tapfour',420			devicemotion_shake01: 'shake',421			devicemotion_shake02: 'shakefrontback',422			devicemotion_shake03: 'shakeleftright',423			devicemotion_shake04: 'shakeupdown'424		},425		/**426		* Add gesture events inside the jQuery.event.special namespace427		*/428		function( sInternal_, sPublicFN_ ) {429			// add as funciton to jQuery.event.special.sPublicFN_430			jQuery.event.special[ sPublicFN_ ] = {431				/**432				* When the first event handler is bound, jQuery executes the setup function.433				* This plugin just uses one eventhandler per element, regardless of the number of bound events.434				* All Events are stored internally as properties on the dom-element using the $.data api.435				* The setup-function adds the eventlistener, acting as a proxy function for the internal events.436				* $.data.ojQueryGestures[_sDOMEvent ('tap') ] = {Boolean}437				* @return {Void}438				*/439				setup: function () {440					// split the arguments to necessary controll arguements441					var _aSplit = sInternal_.split('_');442					var _sDOMEvent = _aSplit[0]; //443					// get the associated gesture event and strip the counter: necessary for distinguisihng similliar events such as tapone-tapfour444					var _sGestureEvent = _aSplit[1].slice(0,_aSplit[1].length-2);445					var _$element = jQuery(this);446					var _oDatajQueryGestures ;447					var oObj;448					// bind the event handler on the first $.bind() for a gestureend-event, set marker449					if (!_$element.data('ojQueryGestures') || !_$element.data('ojQueryGestures')[_sDOMEvent])  {450						// setup pseudo event451						_oDatajQueryGestures = _$element.data('ojQueryGestures') || {};452						oObj = {};453						// marker for:  domEvent being set on this element454						// e.g.: $.data.oGestureInternals['touchstart'] = true;455						// since they're grouped, i'm just marking the first one being added456						oObj[_sDOMEvent] = true;457						$.extend(true,_oDatajQueryGestures,oObj);458						_$element.data('ojQueryGestures' ,_oDatajQueryGestures);459						// add gesture events460						if($.hasGestures) {461							switch(_sGestureEvent) {462								// event: orientationchange463								case 'orientationchange':464									_$element.get(0).addEventListener('orientationchange', _onOrientationchange, false);465								break;466								// event:467								// - shake468								// - tilt469								case 'shake':470								case 'shakefrontback':471								case 'shakeleftright':472								case 'shakeupdown':473								case 'tilt':474									//$.hasGyroscope = true //!window.DeviceOrientationEvent;475									//_$element.get(0).addEventListener('devicemotion', _onDevicemotion, false);476									//_$element.get(0).addEventListener('deviceorientation', _onDeviceorientation, false);477									_$element.get(0).addEventListener('devicemotion', _onDevicemotion, false);478								break;479								// event:480								// - touchstart481								// - touchmove482								// - touchend483								case 'tap':484								case 'swipe':485								case 'swipeup':486								case 'swiperightup':487								case 'swiperight':488								case 'swiperightdown':489								case 'swipedown':490								case 'swipeleftdown':491								case 'swipeleft':492									_$element.get(0).addEventListener('touchstart', _onTouchstart, false);493								break;494								// event: gestureend495								case 'pinchopen':496								case 'pinchclose' :497								case 'rotatecw' :498								case 'rotateccw' :499									_$element.get(0).addEventListener('gesturestart', _onGesturestart, false);500									_$element.get(0).addEventListener('gestureend', _onGestureend, false);501								break;502								// event: gesturechange503								case 'pinch':504								case 'rotate':505									_$element.get(0).addEventListener('gesturestart', _onGesturestart, false);506									_$element.get(0).addEventListener('gesturechange', _onGesturechange, false);507								break;508							}509						}510						// create substitute for gesture events511						else {512							switch(_sGestureEvent) {513								// event substitutes:514								// - touchstart: mousedown515								// - touchmove: none516								// - touchend: mouseup517								case 'tap':518								case 'swipe':519									// _$element.get(0).addEventListener('mousedown', _onTouchstart, false);520									 _$element.bind('mousedown', _onTouchstart);521								break;522								// no substitution523								case 'orientationchange':524								case 'pinchopen':525								case 'pinchclose' :526								case 'rotatecw' :527								case 'rotateccw' :528								case 'pinch':529								case 'rotate':530								case 'shake':531								case 'tilt':532								break;533							}534						}535					}536					return false;537				},538				/**539				* For every $.bind(GESTURE) the add-function will be called.540				* Instead of binding an actual eventlister, the event is stored as $.data on the element.541				* The handler will be triggered using $.triggerHandler(GESTURE) if the internal542				* eventhandler (proxy being bound on setup()) detects a GESTURE event543				* @param {Object} event_ jQuery-Event-Object being passed by $.bind()544				* @return {Void}545				*/546				add : function(event_) {547					// add pseudo event: properties on $.data548					var _$element = jQuery(this);549					var _oDatajQueryGestures = _$element.data('ojQueryGestures');550//					_oDatajQueryGestures[event_.type] = { 'originalType' : event_.type , 'threshold' : event_.data.threshold, 'preventDefault' : event_.data.preventDefault } ;551					_oDatajQueryGestures[event_.type] = { 'originalType' : event_.type } ;552					return false;553				},554				/**555				* For every $.unbind(GESTURE) the remove-function will be called.556				* Instead of removing the actual eventlister, the event is removed from $.data on the element.557				* @param {Object} event_ jQuery-Event-Object being passed by $.bind()558				* @return {Void}559				*/560				remove : function(event_) {561					// remove pseudo event: properties on $.data562					var _$element = jQuery(this);563					var _oDatajQueryGestures = _$element.data('ojQueryGestures');564					_oDatajQueryGestures[event_.type] = false;565					_$element.data('ojQueryGestures' ,_oDatajQueryGestures );566					return false;567				},568				/**569				* The last $.unbind()-call on the domElement triggers the teardown function570				* removing the eventlistener571				* @return {Void}572				*/573				// @TODO: maybe rework teardown to work with event type?!574				teardown : function() {575					// split the arguments to necessary controll arguements576					var _aSplit = sInternal_.split('_');577					var _sDOMEvent = _aSplit[0]; //578					// get the associated gesture event and strip the counter: necessary for distinguisihng similliar events such as tapone-tapfour579					var _sGestureEvent = _aSplit[1].slice(0,_aSplit[1].length-2);580					var _$element = jQuery(this);581					var _oDatajQueryGestures;582					var oObj;583					// bind the event handler on the first $.bind() for a gestureend-event, set marker584					if (!_$element.data('ojQueryGestures') || !_$element.data('ojQueryGestures')[_sDOMEvent])  {585						// setup pseudo event586						_oDatajQueryGestures = _$element.data('ojQueryGestures') || {};587						oObj = {};588						// remove marker for:  domEvent being set on this element589						oObj[_sDOMEvent] = false;590						$.extend(true,_oDatajQueryGestures,oObj);591						_$element.data('ojQueryGestures' ,_oDatajQueryGestures);592						// remove gesture events593						if($.hasGestures) {594							switch(_sGestureEvent) {595								// event: orientationchange596								case 'orientationchange':597									_$element.get(0).removeEventListener('orientationchange', _onOrientationchange, false);598								break;599								case 'shake':600								case 'shakefrontback':601								case 'shakeleftright':602								case 'shakeupdown':603								case 'tilt':604									_$element.get(0).removeEventListener('devicemotion', _onDevicemotion, false);605								break;606								// event :607								// - touchstart608								// - touchmove609								// - touchend610								case 'tap':611								case 'swipe':612								case 'swipeup':613								case 'swiperightup':614								case 'swiperight':615								case 'swiperightdown':616								case 'swipedown':617								case 'swipeleftdown':618								case 'swipeleft':619								case 'swipeleftup':620									_$element.get(0).removeEventListener('touchstart', _onTouchstart, false);621									_$element.get(0).removeEventListener('touchmove', _onTouchmove, false);622									_$element.get(0).removeEventListener('touchend', _onTouchend, false);623								break;624								// event: gestureend625								case 'pinchopen':626								case 'pinchclose' :627								case 'rotatecw' :628								case 'rotateccw' :629									_$element.get(0).removeEventListener('gesturestart', _onGesturestart, false);630									_$element.get(0).removeEventListener('gestureend', _onGestureend, false);631								break;632								// event: gesturechange633								case 'pinch':634								case 'rotate':635									_$element.get(0).removeEventListener('gesturestart', _onGesturestart, false);636									_$element.get(0).removeEventListener('gesturechange', _onGesturechange, false);637								break;638							}639						}640						// remove substitute for gesture events641						else {642							switch(_sGestureEvent) {643								// event substitutes:644								// - touchstart: mousedown645								// - touchmove: none646								// - touchend: mouseup647								case 'tap':648								case 'swipe':649//									_$element.get(0).removeEventListener('mousedown', _onTouchstart, false);650//									_$element.get(0).removeEventListener('mousemove', _onTouchmove, false);651//									_$element.get(0).removeEventListener('mouseup', _onTouchend, false);652									_$element.unbind('mousedown', _onTouchstart);653									_$element.unbind('mousemove', _onTouchmove);654									_$element.unbind('mouseup', _onTouchend);655								break;656								// no substitution657								case 'orientationchange':658								case 'pinchopen':659								case 'pinchclose' :660								case 'rotatecw' :661								case 'rotateccw' :662								case 'pinch':663								case 'rotate':664								case 'shake':665								case 'tilt':666								break;667							}668						}669					}670				return false;671				}672			};673		});674	/**675	* Creates the object that ist passed as second argument to the $element.triggerHandler function.676	* This object contains detailed informations about the gesture event.677	* @param {Object} oOptions_  {type: {String}, touches: {String}, deltaY: {String},deltaX : {String}, startMove: {Object}, event:{DOM-Event}, timestamp:{String},vector: {Number}}678	* @example _createOptions (679	*				{680	*					type: 'swipemove',681	*					touches: '1',682	*					deltaY: _iDeltaY,683	*					deltaX : _iDeltaX,684	*					startMove: _oDatajQueryGestures.oStartTouch,685	*					event:event_,686	*					timestamp:_oEventData.timestamp,687	*					vector: -1688	*				}689	*			);690	* @returns {Object}691	*			{692	*				type: eventtype e.g. "swipe","pinch",693	*				originalEvent: {DOM-Event},694	*				// default: just one entry on the delta-array - the first touchpoint695	*				// the first touchpoint is the reference point for every gesture,696	*				// because moving touchpoints in various directions would result in697	*				// a gesture.698	*				// delta and direction details are just provided for touch not for gesture / motion events699	*				delta : [700	*					{701	*						lastX:{Number} , // x-axis: relative to the last touchevent (e.g. touchmove!)702	*						lastY:{Number}, // y-axis: relative to the last touchevent (e.g. touchmove!)703	*						moved: {Number},  // distance: relative to the original touchpoint704	*						startX: {Number} , // relative to the original touchpoint705	*						startY: {Number} ,// relative to the original touchpoint706	*					} ],707	*				// based on the first touchpoint708	*				direction : { // relative to the last touchevent (e.g. touchmove!)709	*					vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)710	*					orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)711	*					lastX : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)712	*					lastY : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)713	*					startX: {Number} , //-1,0,+1 relative to the original touchpoint714	*					startY: {Number} ,// -1,0,+1 relative to the original touchpoint715	*				},716	*				rotation: {Number} || null, // gestureonly: amount of rotation relative to the current position NOT the original717	*				scale: {Number} || null, // gestureonly: amount of scaling relative to the current position NOT the original718	*				duration: {Number}, // ms: relative to the original touchpoint719	*				description : {String} // details as String: {TYPE *}:{TOUCHES 1|2|3|4}:{X-AXIS 'right'|'left'|'steady'}:{Y-AXIS 'down'|'up'|'steady'} e.g. "swipe:1:left:steady" relative to the last touchpoint720	*			};721	*/722	function _createOptions(oOptions_) {723		// force properties724		oOptions_.startMove = (oOptions_.startMove) ? oOptions_.startMove : {startX: null,startY:null,timestamp:null}  ;725		var _iNow = new Date().getTime();726		var _oDirection;727		var _oDelta;728		// calculate touch differences729		if (oOptions_.touches) {730			// store delta values731			_oDelta = [732				{733					lastX: oOptions_.deltaX ,734					lastY: oOptions_.deltaY,735					moved: null,736					startX:  oOptions_.screenX - oOptions_.startMove.screenX ,737					startY: oOptions_.screenY - oOptions_.startMove.screenY738				}739			];740			_oDirection =  {741				vector: oOptions_.vector || null,742				orientation : window.orientation || null,743				lastX : ((_oDelta[0].lastX > 0) ? +1 : ( (_oDelta[0].lastX < 0) ? -1 : 0 ) ),744				lastY : ((_oDelta[0].lastY > 0) ? +1 : ( (_oDelta[0].lastY < 0) ? -1 : 0 ) ),745				startX : ((_oDelta[0].startX > 0) ? +1 : ( (_oDelta[0].startX < 0) ? -1 : 0 ) ),746				startY : ((_oDelta[0].startY > 0) ? +1 : ( (_oDelta[0].startY < 0) ? -1 : 0 ) )747			};748			// calculate distance traveled using the pythagorean theorem749			_oDelta[0].moved =  Math.sqrt(Math.pow(Math.abs(_oDelta[0].startX), 2) + Math.pow(Math.abs(_oDelta[0].startY), 2));750		}751		return {752			type: oOptions_.type || null,753			originalEvent: oOptions_.event || null,754			delta : _oDelta  || null,755			direction : _oDirection || { orientation : window.orientation || null, vector: oOptions_.vector || null},756			duration: (oOptions_.duration) ? oOptions_.duration : ( oOptions_.startMove.timestamp ) ? _iNow - oOptions_.timestamp : null,757			rotation: oOptions_.rotation || null,758			scale: oOptions_.scale || null,759			description : oOptions_.description || [760				oOptions_.type,761				':',762				oOptions_.touches,763				':',764				((_oDelta[0].lastX != 0) ? ((_oDelta[0].lastX > 0) ? 'right' : 'left') : 'steady'),765				':',766				((_oDelta[0].lastY != 0) ? ( (_oDelta[0].lastY > 0) ? 'down' : 'up') :'steady')767				].join('')768		};769	}770	/**771	* DOM-event handlers772	*/773	/**774	* Handler: orientationchange775	* Triggers the bound orientationchange handler on the window element776	* The "orientationchange" handler will receive an object with additional information777	* about the event.778	*  {779	*	direction : {780	*		orientation: {-90|0|90|180}781	*	},782	*	description : [783	*		'orientationchange:{landscape:clockwise:|portrait:default|landscape:counterclockwise|portrait:upsidedown}:{-90|0|90|180}' // e.g. 'orientation:landscape:clockwise:-90784	*	}785	* @param {DOM-Event} event_786	* @return {Void}787	*/788	function _onOrientationchange(event_) {789		// window.orientation: -90,0,90,180790		var _aDict = ['landscape:clockwise:','portrait:default:','landscape:counterclockwise:','portrait:upsidedown:'];791		$(window).triggerHandler('orientationchange',792			{793				direction : {orientation: window.orientation},794				description : [795					'orientationchange:',796					_aDict[( (window.orientation / 90) +1)],797					window.orientation798					].join('')799			});800	}801	/**802	* Handler: devicemotion803	* Calculates "motion events" such as shake, tilt, wiggle by observing "changes in space"804	* For understanding "directions", place your mobile device on a table with the bottom805	* (home button) close to you:806	*  - x-axis: horizontal left / right807	*  - y-axis: horizontal front / back (through the home button)808	*  - z-axis: vertical through your device809	* @param {DOM-Event} event_810	* @returns {Object}811	*			{812	*				type: eventtype e.g. "shake",813	*				originalEvent: {DOM-Event},814	*				// delta and direction details are just provided for touch not for gesture / motion events815	*				delta : null,816	*				direction :{817	*					vector: null,818	*					orientation: -90,0,90,180 || null (window.orienntation)819	*				}820	*				rotation: {Number} , //  amount of rotation relative to the current position NOT the original821	*				scale: {Number} , // amount of scaling relative to the current position NOT the original822	*				duration: {Number}, // ms: duration of the motion823	*				description : {String} // details as String: pinch:{'close'|'open'} e.g. "pinch:-1:close" ||  rotate:{'counterclockwise'|'clockwise'} e.g. "rotate:-1:counterclockwise"824	*			};825	* @param {DOM-Event} event_826	* @return {Void}827	*/828	function _onDevicemotion(event_) {829		var _sType;830		var _$element = jQuery(window);831		//var _bHasGyroscope = $.hasGyroscope;832		// skip custom notification: devicemotion is triggered every 0.05s regardlesse of any gesture833		// get options834		var _oDatajQueryGestures = _$element.data('ojQueryGestures');835		var _oThreshold = $.jGestures.defaults.thresholdShake;836		// get last position or set initital values837		var _oLastDevicePosition = _oDatajQueryGestures.oDeviceMotionLastDevicePosition || {838			accelerationIncludingGravity : {839				x: 0,840				y: 0,841				z: 0842			},843			shake : {844				eventCount: 0,845				intervalsPassed: 0,846				intervalsFreeze: 0847			},848			shakeleftright : {849				eventCount: 0,850				intervalsPassed: 0,851				intervalsFreeze: 0852			},853			shakefrontback : {854				eventCount: 0,855				intervalsPassed: 0,856				intervalsFreeze: 0857			},858			shakeupdown : {859				eventCount: 0,860				intervalsPassed: 0,861				intervalsFreeze: 0862			}863		};864		// cache current values865		var _oCurrentDevicePosition = {866			accelerationIncludingGravity : {867				x: event_.accelerationIncludingGravity.x,868				y: event_.accelerationIncludingGravity.y,869				z: event_.accelerationIncludingGravity.z870			},871			shake: {872				eventCount: _oLastDevicePosition.shake.eventCount,873				intervalsPassed: _oLastDevicePosition.shake.intervalsPassed,874				intervalsFreeze: _oLastDevicePosition.shake.intervalsFreeze875			 },876			 shakeleftright: {877				eventCount: _oLastDevicePosition.shakeleftright.eventCount,878				intervalsPassed: _oLastDevicePosition.shakeleftright.intervalsPassed,879				intervalsFreeze: _oLastDevicePosition.shakeleftright.intervalsFreeze880			 },881			 shakefrontback: {882				eventCount: _oLastDevicePosition.shakefrontback.eventCount,883				intervalsPassed: _oLastDevicePosition.shakefrontback.intervalsPassed,884				intervalsFreeze: _oLastDevicePosition.shakefrontback.intervalsFreeze885			 },886			 shakeupdown: {887				eventCount: _oLastDevicePosition.shakeupdown.eventCount,888				intervalsPassed: _oLastDevicePosition.shakeupdown.intervalsPassed,889				intervalsFreeze: _oLastDevicePosition.shakeupdown.intervalsFreeze890			 }891		};892		// options893		var _aType;894		var _aDescription;895		var _oObj;896		// trigger events for all bound pseudo events on this element897		for (_sType in _oDatajQueryGestures) {898			// get current pseudo event899			// trigger bound events on this element900			switch(_sType) {901				case 'shake':902				case 'shakeleftright':903				case 'shakefrontback':904				case 'shakeupdown':905					// options906					_aType = [];907					_aDescription = [];908					_aType.push(_sType);909					// freeze shake - prevent multiple shake events on one  shaking motion (user won't stop shaking immediately)910					if (++_oCurrentDevicePosition[_sType].intervalsFreeze > _oThreshold.freezeShakes && _oCurrentDevicePosition[_sType].intervalsFreeze < (2*_oThreshold.freezeShakes) ) { break;	}911					// set control values912					_oCurrentDevicePosition[_sType].intervalsFreeze  = 0;913					_oCurrentDevicePosition[_sType].intervalsPassed++;914					// check for shaking motions: massive acceleration changes in every direction915					if ( ( _sType === 'shake' ||_sType === 'shakeleftright' ) && ( _oCurrentDevicePosition.accelerationIncludingGravity.x > _oThreshold.leftright.sensitivity  || _oCurrentDevicePosition.accelerationIncludingGravity.x < (-1* _oThreshold.leftright.sensitivity) ) ) {916						_aType.push('leftright');917						_aType.push('x-axis');918					}919					if ( ( _sType === 'shake' ||_sType === 'shakefrontback' ) && (_oCurrentDevicePosition.accelerationIncludingGravity.y > _oThreshold.frontback.sensitivity  || _oCurrentDevicePosition.accelerationIncludingGravity.y < (-1 * _oThreshold.frontback.sensitivity) ) ) {920						_aType.push('frontback');921						_aType.push('y-axis');922					}923					if ( ( _sType === 'shake' ||_sType === 'shakeupdown' ) && ( _oCurrentDevicePosition.accelerationIncludingGravity.z+9.81 > _oThreshold.updown.sensitivity  || _oCurrentDevicePosition.accelerationIncludingGravity.z+9.81 < (-1 * _oThreshold.updown.sensitivity) ) ) {924						_aType.push('updown');925						_aType.push('z-axis');926					}927					// at least one successful shaking event928					if (_aType.length > 1) {929						// minimum number of shaking motions during  the defined "time" (messured by events - device event interval: 0.05s)930						if (++_oCurrentDevicePosition[_sType].eventCount == _oThreshold.requiredShakes && (_oCurrentDevicePosition[_sType].intervalsPassed) < _oThreshold.freezeShakes ) {931							// send event932							_$element.triggerHandler(_sType, _createOptions ({type: _sType, description: _aType.join(':'), event:event_,duration:_oCurrentDevicePosition[_sType].intervalsPassed*5 }) );933							// reset934							_oCurrentDevicePosition[_sType].eventCount = 0;935							_oCurrentDevicePosition[_sType].intervalsPassed = 0;936							// freeze shake937							_oCurrentDevicePosition[_sType].intervalsFreeze = _oThreshold.freezeShakes+1;938						}939						// too slow, reset940						else if (_oCurrentDevicePosition[_sType].eventCount == _oThreshold.requiredShakes && (_oCurrentDevicePosition[_sType].intervalsPassed) > _oThreshold.freezeShakes ) {941							_oCurrentDevicePosition[_sType].eventCount = 0 ;942							_oCurrentDevicePosition[_sType].intervalsPassed = 0;943						}944					}945				break;946			}947			// refresh pseudo events948			_oObj = {};949			_oObj.oDeviceMotionLastDevicePosition = _oCurrentDevicePosition;950			_$element.data('ojQueryGestures',$.extend(true,_oDatajQueryGestures,_oObj));951		}952	}953	/**954	* Handler: touchstart or mousedown955	* Setup pseudo-event by storing initial values such as :956	*	screenX : {Number}957	*	screenY : {Number}958	*	timestamp: {Number}959	*  on the pseudo gesture event and960	*  sets up additional eventlisteners for handling touchmove events.961	* @param {DOM-Event} event_962	* @return {Void}963	*/964	function _onTouchstart(event_) {965		// ignore bubbled handlers966		// if ( event_.currentTarget !== event_.target ) { return; }967		var _$element = jQuery(event_.currentTarget);968		// var _$element = jQuery(event_.target);969		// trigger custom notification970		_$element.triggerHandler($.jGestures.events.touchstart,event_);971		// set the necessary touch events972		if($.hasGestures) {973			event_.currentTarget.addEventListener('touchmove', _onTouchmove, false);974			event_.currentTarget.addEventListener('touchend', _onTouchend, false);975		}976		// event substitution977		else {978//			event_.currentTarget.addEventListener('mousemove', _onTouchmove, false);979//			event_.currentTarget.addEventListener('mouseup', _onTouchend, false);980			_$element.bind('mousemove', _onTouchmove);981			_$element.bind('mouseup', _onTouchend);982		}983		// get stored pseudo event984		var _oDatajQueryGestures = _$element.data('ojQueryGestures');985		// var _oEventData = _oDatajQueryGestures[_sType];986		var _eventBase = (event_.touches) ? event_.touches[0] : event_;987		// store current values for calculating relative values (changes between touchmoveevents)988		var _oObj = {};989		_oObj.oLastSwipemove = { screenX : _eventBase.screenX, screenY : _eventBase.screenY, timestamp:new Date().getTime()};990		_oObj.oStartTouch = { screenX : _eventBase.screenX, screenY : _eventBase.screenY, timestamp:new Date().getTime()};991		_$element.data('ojQueryGestures',$.extend(true,_oDatajQueryGestures,_oObj));992	}993	/**994	* Handler: touchmove or mousemove995	* Calculates the x/y changes since the last event,996	* compares it to $.jGestures.defaults.thresholdMove and triggers997	* an swipemove event if the distance exceed the998	* threshold.999	* Custom-event argument object:1000	* {Object}1001	*			{1002	*				type: e.g. 'swipemove',1003	*				¡Ö: {DOM-Event},1004	*				// default: just one entry on the delta-array - the first touchpoint1005	*				// the first touchpoint is the reference point for every gesture,1006	*				// because moving touchpoints in various directions would result in1007	*				// a gesture.1008	*				// delta and direction details are just provided for touch not for gesture / motion events1009	*				delta : [1010	*					{1011	*						lastX:{Number} , // x-axis: relative to the last touchevent (e.g. touchmove!)1012	*						lastY:{Number}, // y-axis: relative to the last touchevent (e.g. touchmove!)1013	*						moved: {Number},  // distance: relative to the original touchpoint1014	*						startX: {Number} , // relative to the original touchpoint1015	*						startY: {Number} ,// relative to the original touchpoint1016	*					} ],1017	*				// based on the first touchpoint1018	*				direction : { // relative to the last touchevent (e.g. touchmove!)1019	*					vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)1020	*					orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)1021	*					lastX : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)1022	*					lastY : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)1023	*					startX: {Number} , //-1,0,+1 relative to the original touchpoint1024	*					startY: {Number} ,// -1,0,+1 relative to the original touchpoint1025	*				},1026	*				rotation: null, // gestureonly: amount of rotation relative to the current position NOT the original1027	*				scale: null, // gestureonly: amount of scaling relative to the current position NOT the original1028	*				duration: {Number}, // ms: relative to the original touchpoint1029	*				description : {String} // details as String: {TYPE *}:{TOUCHES 1|2|3|4}:{X-AXIS 'right'|'left'|'steady'}:{Y-AXIS 'down'|'up'|'steady'} e.g. "swipe:1:left:steady" relative to the last touchpoint1030	*			};1031	*1032	* @param {DOM-Event} event_1033	* @return {Void}1034	*/1035	function _onTouchmove(event_) {1036		var _$element = jQuery(event_.currentTarget);1037		// var _$element = jQuery(event_.target);1038		// get stored pseudo event1039		var _oDatajQueryGestures = _$element.data('ojQueryGestures');1040		var _bHasTouches = !!event_.touches;1041		var _iScreenX = (_bHasTouches) ? event_.changedTouches[0].screenX : event_.screenX;1042		var _iScreenY = (_bHasTouches) ? event_.changedTouches[0].screenY : event_.screenY;1043		//relative to the last event1044		var _oEventData = _oDatajQueryGestures.oLastSwipemove;1045		var _iDeltaX = _iScreenX - _oEventData.screenX   ;1046		var _iDeltaY = _iScreenY - _oEventData.screenY;1047		var _oDetails;1048			// there's a swipemove set (not the first occurance), trigger event1049		if (!!_oDatajQueryGestures.oLastSwipemove) {1050			// check1051			_oDetails = _createOptions({type: 'swipemove', touches: (_bHasTouches) ? event_.touches.length: '1', screenY: _iScreenY,screenX:_iScreenX ,deltaY: _iDeltaY,deltaX : _iDeltaX, startMove:_oEventData, event:event_, timestamp:_oEventData.timestamp});1052			_$element.triggerHandler(_oDetails.type,_oDetails);1053		}1054		// store the new values1055		var _oObj = {};1056		var _eventBase = (event_.touches) ? event_.touches[0] : event_;1057		_oObj.oLastSwipemove = { screenX : _eventBase.screenX, screenY : _eventBase.screenY, timestamp:new Date().getTime()};1058		_$element.data('ojQueryGestures',$.extend(true,_oDatajQueryGestures,_oObj));1059	}1060	/**1061	* Handler: touchend or mouseup1062	* Removes the additional handlers (move/end)1063	* Calculates the x/y changes since the touchstart event1064	* not in relation to the last move event.1065	* Triggers the1066	*	swipeone|swipetwo|swipethree|swipefour|1067	*	swipeup|swiperightup|swiperight|swiperightdown|swipedown|1068	*	swipeleftdown|swipeleft|swipeleftup|1069	*	tapone|taptwo|tapthree|tapfour1070	* event.1071	*		{Object}1072	*			{1073	*				type: eventtype e.g. "swipeone","swipeleftdown",1074	*				originalEvent: {DOM-Event},1075	*				// default: just one entry on the delta-array - the first touchpoint1076	*				// the first touchpoint is the reference point for every gesture,1077	*				// because moving touchpoints in various directions would result in1078	*				// a gesture.1079	*				// delta and direction details are just provided for touch not for gesture / motion events1080	*				delta : [1081	*					{1082	*						lastX:{Number} , // x-axis: relative to the last touchevent (e.g. touchmove!)1083	*						lastY:{Number}, // y-axis: relative to the last touchevent (e.g. touchmove!)1084	*						moved: {Number},  // distance: relative to the original touchpoint1085	*						startX: {Number} , // relative to the original touchpoint1086	*						startY: {Number} ,// relative to the original touchpoint1087	*					} ],1088	*				// based on the first touchpoint1089	*				direction : { // relative to the last touchevent (e.g. touchmove!)1090	*					vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)1091	*					orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)1092	*					lastX : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)1093	*					lastY : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)1094	*					startX: {Number} , //-1,0,+1 relative to the original touchpoint1095	*					startY: {Number} ,// -1,0,+1 relative to the original touchpoint1096	*				},1097	*				rotation: null,1098	*				scale: null ,1099	*				duration: {Number}, // ms: relative to the original touchpoint1100	*				description : {String} // details as String: {TYPE *}:{TOUCHES 1|2|3|4}:{X-AXIS 'right'|'left'|'steady'}:{Y-AXIS 'down'|'up'|'steady'} e.g. "swipe:1:left:steady" relative to the last touchpoint1101	*			};1102	* @param {DOM-Event} event_1103	* @return {Void}1104	*/1105	function _onTouchend(event_) {1106		// ignore bubbled handlers1107		// if ( event_.currentTarget !== event_.target ) { return; }1108		var _$element = jQuery(event_.currentTarget);1109		var _bHasTouches = !!event_.changedTouches;1110		var _iTouches = (_bHasTouches) ? event_.changedTouches.length : '1';1111		var _iScreenX = (_bHasTouches) ? event_.changedTouches[0].screenX : event_.screenX;1112		var _iScreenY = (_bHasTouches) ? event_.changedTouches[0].screenY : event_.screenY;1113		// trigger custom notification1114		_$element.triggerHandler($.jGestures.events.touchendStart,event_);1115		// var _$element = jQuery(event_.target);1116		// remove events1117		if($.hasGestures) {1118			event_.currentTarget.removeEventListener('touchmove', _onTouchmove, false);1119			event_.currentTarget.removeEventListener('touchend', _onTouchend, false);1120		}1121		// event substitution1122		else {1123//			event_.currentTarget.removeEventListener('mousemove', _onTouchmove, false);1124//			event_.currentTarget.removeEventListener('mouseup', _onTouchend, false);1125			_$element.unbind('mousemove', _onTouchmove);1126			_$element.unbind('mouseup', _onTouchend);1127		}1128		// get all bound pseudo events1129		var _oDatajQueryGestures = _$element.data('ojQueryGestures');1130		// if the current change on the x/y position is above the defined threshold for moving an element set the moved flag1131		// to distinguish between a moving gesture and a shaking finger trying to tap1132		var _bHasMoved = (1133			Math.abs(_oDatajQueryGestures.oStartTouch.screenX - _iScreenX) > $.jGestures.defaults.thresholdMove ||1134			Math.abs(_oDatajQueryGestures.oStartTouch.screenY - _iScreenY) > $.jGestures.defaults.thresholdMove1135		) ? true : false;1136		// if the current change on the x/y position is above the defined threshold for swiping set the moved flag1137		// to indicate we're dealing with a swipe gesture1138		var _bHasSwipeGesture = (1139			Math.abs(_oDatajQueryGestures.oStartTouch.screenX - _iScreenX) > $.jGestures.defaults.thresholdSwipe ||1140			Math.abs(_oDatajQueryGestures.oStartTouch.screenY - _iScreenY) > $.jGestures.defaults.thresholdSwipe1141		) ? true : false;1142		var _sType;1143		var _oEventData ;1144		var _oDelta;1145		// calculate distances in relation to the touchstart position not the last touchmove event!1146		var _iDeltaX;1147		var _iDeltaY;1148		var _oDetails;1149		var _aDict = ['zero','one','two','three','four'];1150		// swipe marker1151		var _bIsSwipe;1152		// trigger events for all bound pseudo events on this element1153		for (_sType in _oDatajQueryGestures) {1154			// get current pseudo event1155			_oEventData = _oDatajQueryGestures.oStartTouch;1156			_oDelta = {};1157			_iScreenX = (_bHasTouches) ? event_.changedTouches[0].screenX : event_.screenX;1158			_iScreenY = (_bHasTouches) ? event_.changedTouches[0].screenY : event_.screenY;1159			// calculate distances in relation to the touchstart position not the last touchmove event!1160			_iDeltaX = _iScreenX - _oEventData.screenX ;1161			_iDeltaY = _iScreenY - _oEventData.screenY;1162			_oDetails = _createOptions({type: 'swipe', touches: _iTouches, screenY: _iScreenY,screenX:_iScreenX ,deltaY: _iDeltaY,deltaX : _iDeltaX, startMove:_oEventData, event:event_, timestamp:  _oEventData.timestamp });1163			// swipe marker1164			_bIsSwipe = false;1165			// trigger bound events on this element1166			switch(_sType) {1167				case 'swipeone':1168					if( _bHasTouches === false && _iTouches == 1 && _bHasMoved === false){1169						// trigger tapone!1170						break;1171					}1172					if (_bHasTouches===false || ( _iTouches == 1  && _bHasMoved === true && _bHasSwipeGesture===true)) {1173						_bIsSwipe = true;1174						_oDetails.type = ['swipe',_aDict[_iTouches]].join('');1175						_$element.triggerHandler(_oDetails.type,_oDetails);1176					}1177				break;1178				case 'swipetwo':1179					if (( _bHasTouches && _iTouches== 2 && _bHasMoved === true && _bHasSwipeGesture===true)) {1180						_bIsSwipe = true;1181						_oDetails.type = ['swipe',_aDict[_iTouches]].join('');1182						_$element.triggerHandler(_oDetails.type,_oDetails);1183					}1184				break;1185				case 'swipethree':1186					if ( ( _bHasTouches && _iTouches == 3 && _bHasMoved === true && _bHasSwipeGesture===true)) {1187						_bIsSwipe = true;1188						_oDetails.type = ['swipe',_aDict[_iTouches]].join('');1189						_$element.triggerHandler(_oDetails.type,_oDetails);1190					}1191				break;1192				case 'swipefour':1193					if ( ( _bHasTouches && _iTouches == 4 && _bHasMoved === true && _bHasSwipeGesture===true)) {1194						_bIsSwipe = true;1195						_oDetails.type = ['swipe',_aDict[_iTouches]].join('');1196						_$element.triggerHandler(_oDetails.type,_oDetails);1197					}1198				break;1199				case 'swipeup':1200				case 'swiperightup':1201				case 'swiperight':1202				case 'swiperightdown':1203				case 'swipedown':1204				case 'swipeleftdown':1205				case 'swipeleft':1206				case 'swipeleftup':1207					if ( _bHasTouches && _bHasMoved === true && _bHasSwipeGesture===true) {1208						_bIsSwipe = true;1209						_oDetails.type = [1210									'swipe',1211								((_oDetails.delta[0].lastX != 0) ? ((_oDetails.delta[0].lastX > 0) ? 'right' : 'left') : ''),1212								((_oDetails.delta[0].lastY != 0) ? ((_oDetails.delta[0].lastY > 0) ? 'down' : 'up') :'')1213									].join('');1214						_$element.triggerHandler(_oDetails.type, _oDetails);1215					}1216				break;1217				case 'tapone':1218				case 'taptwo':1219				case 'tapthree':1220				case 'tapfour':1221					if (( /* _bHasTouches && */ _bHasMoved !== true && _bIsSwipe !==true) && (_aDict[_iTouches] ==_sType.slice(3)) ) {1222						_oDetails.description = ['tap',_aDict[_iTouches]].join('');1223						_oDetails.type = ['tap',_aDict[_iTouches]].join('');1224						_$element.triggerHandler(_oDetails.type,_oDetails);1225						}1226					break;1227			}1228			// refresh pseudo events1229			var _oObj = {};1230//			_oObj[_sType] = false;1231//			_oObj.hasTouchmoved = false;1232			_$element.data('ojQueryGestures',$.extend(true,_oDatajQueryGestures,_oObj));1233			_$element.data('ojQueryGestures',$.extend(true,_oDatajQueryGestures,_oObj));1234		}1235		_$element.triggerHandler($.jGestures.events.touchendProcessed,event_);1236	}1237	/**1238	* Handler: gesturestart1239	* Setup pseudo-event by storing initial values such as :1240	*	timestamp: {Number}1241	*  on the pseudo gesture event1242	* Since the gesture-event doesn't supply event.touches no tuchpoints will be calculated1243	* @param {DOM-Event} event_1244	* @return {Void}1245	*/1246	function _onGesturestart(event_) {1247		// ignore bubbled handlers1248		// if ( event_.currentTarget !== event_.target ) { return; }1249		var _$element = jQuery(event_.currentTarget);1250		// var _$element = jQuery(event_.target);1251		// trigger custom notification1252		_$element.triggerHandler($.jGestures.events.gesturestart,event_);1253		// get stored pseudo event1254		var _oDatajQueryGestures = _$element.data('ojQueryGestures');1255		// var _oEventData = _oDatajQueryGestures[_sType];1256		// store current values for calculating relative values (changes between touchmoveevents)1257		var _oObj = {};1258		_oObj.oStartTouch = {timestamp:new Date().getTime()};1259		_$element.data('ojQueryGestures',$.extend(true,_oDatajQueryGestures,_oObj));1260	}1261	/**1262	* Handler: gesturechange1263	* Read the event_.scale / event_.rotate values,1264	* an triggers a pinch|rotate event if necessary.1265	* Since the gesture-event doesn't supply event.touches no tuchpoints will be calculated1266	* @returns {Object}1267	*			{1268	*				type: eventtype e.g. "pinch","rotate",1269	*				originalEvent: {DOM-Event},1270	*				// delta and direction details are just provided for touch not for gesture / motion events1271	*				delta : null,1272	*				direction : {1273	*					vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)1274	*					 orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)1275	*				 },1276	*				rotation: {Number} , //  amount of rotation relative to the current position NOT the original1277	*				scale: {Number} , // amount of scaling relative to the current position NOT the original1278	*				duration: {Number}, // ms: relative to the original touchpoint1279	*				description : {String} // details as String: pinch:{'close'|'open'} e.g. "pinch:-1:close" ||  rotate:{'counterclockwise'|'clockwise'} e.g. "rotate:-1:counterclockwise"1280	*			};1281	* @param {DOM-Event} event_1282	* @return {Void}1283	*/1284	function _onGesturechange(event_) {1285		// ignore bubbled handlers1286		// if ( event_.currentTarget !== event_.target ) { return; }1287		var _$element = jQuery(event_.currentTarget);1288		// var _$element = jQuery(event_.target);1289		var _iDelta,_iDirection,_sDesc,_oDetails;1290		// get all pseudo events1291		var _oDatajQueryGestures = _$element.data('ojQueryGestures');1292		// trigger events for all bound pseudo events on this element1293		var _sType;1294		for (_sType in _oDatajQueryGestures) {1295			// trigger a specific bound event1296			switch(_sType) {1297				case 'pinch':1298					_iDelta = event_.scale;1299					if ( ( ( _iDelta < 1 ) && (_iDelta % 1) < (1 - $.jGestures.defaults.thresholdPinchclose) ) || ( ( _iDelta > 1 ) && (_iDelta % 1) > ($.jGestures.defaults.thresholdPinchopen) ) ) {1300						_iDirection = (_iDelta < 1 ) ? -1 : +1 ;1301						_oDetails = _createOptions({type: 'pinch', scale: _iDelta, touches: null,startMove:_oDatajQueryGestures.oStartTouch, event:event_, timestamp: _oDatajQueryGestures.oStartTouch.timestamp, vector:_iDirection, description: ['pinch:',_iDirection,':' , ( (_iDelta < 1 ) ? 'close' : 'open' )].join('') });1302						_$element.triggerHandler(_oDetails.type, _oDetails);1303					}1304				break;1305				case 'rotate':1306					_iDelta = event_.rotation;1307					if ( ( ( _iDelta < 1 ) &&  ( -1*(_iDelta) > $.jGestures.defaults.thresholdRotateccw ) ) || ( ( _iDelta > 1 ) && (_iDelta  > $.jGestures.defaults.thresholdRotatecw) ) ) {1308						_iDirection = (_iDelta < 1 ) ? -1 : +1 ;1309						_oDetails = _createOptions({type: 'rotate', rotation: _iDelta, touches: null, startMove:_oDatajQueryGestures.oStartTouch, event:event_, timestamp: _oDatajQueryGestures.oStartTouch.timestamp, vector:_iDirection, description: ['rotate:',_iDirection,':' , ( (_iDelta < 1 ) ? 'counterclockwise' : 'clockwise' )].join('') });1310						_$element.triggerHandler(_oDetails.type, _oDetails);1311					}1312				break;1313			}1314		}1315	}1316	/**1317	* Handler: gestureend1318	* Read the event_.scale / event_.rotate values,1319	* compares it to $.jGestures.defaults.threshold* and triggers1320	* a pinchclose|pinchclose|rotatecw|rotateccw event if the distance exceed the1321	* Since the gesture-event doesn't supply event.touches no tuchpoints will be calculated1322	* * Custom-event argument object:1323	* @returns {Object}1324	*			{1325	*				type: eventtype e.g. "pinchclose","pinchopen", "rotatecw", "rotateccw",1326	*				originalEvent: {DOM-Event},1327	*				// delta and direction details are just provided for touch not for gesture / motion events1328	*				delta : null,1329	*				// based on the first touchpoint1330	*				direction : {1331	*					vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)1332	*					orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)1333	*				},1334	*				rotation: {Number} , //  amount of rotation relative to the current position NOT the original1335	*				scale: {Number} , // amount of scaling relative to the current position NOT the original1336	*				duration: {Number}, // ms: relative to the original touchpoint1337	*				description : {String} // details as String: pinch:{'close'|'open'} e.g. "pinch:-1:close" ||  rotate:{'counterclockwise'|'clockwise'} e.g. "rotate:-1:counterclockwise"1338	*			};1339	* @param {DOM-Event} event_1340	* @return {Void}1341	*/1342	function _onGestureend(event_) {1343		// ignore bubbled handlers1344		// if ( event_.currentTarget !== event_.target ) { return; }1345		var _$element = jQuery(event_.currentTarget);1346		// var _$element = jQuery(event_.target);1347		// trigger custom notification1348		_$element.triggerHandler($.jGestures.events.gestureendStart,event_);1349		var _iDelta;1350		var _oDatajQueryGestures = _$element.data('ojQueryGestures');1351		// trigger handler for every bound event1352		var _sType;1353		for (_sType in _oDatajQueryGestures) {1354			switch(_sType) {1355				case 'pinchclose':1356					_iDelta = event_.scale;1357					if (( _iDelta < 1 ) && (_iDelta % 1) < (1 - $.jGestures.defaults.thresholdPinchclose)) {1358						_$element.triggerHandler('pinchclose', _createOptions ({type: 'pinchclose', scale:_iDelta, vector: -1, touches: null, startMove: _oDatajQueryGestures.oStartTouch, event:event_, timestamp:_oDatajQueryGestures.oStartTouch.timestamp,description: 'pinch:-1:close' }) );1359					}1360				break;1361				case 'pinchopen':1362					_iDelta = event_.scale;1363					if ( ( _iDelta > 1 ) && (_iDelta % 1) > ($.jGestures.defaults.thresholdPinchopen) ) {1364						_$element.triggerHandler('pinchopen', _createOptions ({type: 'pinchopen', scale:_iDelta, vector: +1, touches: null, startMove: _oDatajQueryGestures.oStartTouch, event:event_, timestamp:_oDatajQueryGestures.oStartTouch.timestamp,description: 'pinch:+1:open'}) );1365					}1366				break;1367				case 'rotatecw':1368					_iDelta = event_.rotation;1369					if ( ( _iDelta > 1 ) && (_iDelta  > $.jGestures.defaults.thresholdRotatecw) ) {1370						_$element.triggerHandler('rotatecw', _createOptions ({type: 'rotatecw', rotation:_iDelta, vector: +1, touches: null, startMove: _oDatajQueryGestures.oStartTouch, event:event_, timestamp:_oDatajQueryGestures.oStartTouch.timestamp,description: 'rotate:+1:clockwise'}) );1371					}1372				break;1373				case 'rotateccw':1374					_iDelta = event_.rotation;1375					if ( ( _iDelta < 1 ) &&  ( -1*(_iDelta) > $.jGestures.defaults.thresholdRotateccw ) ) {1376							_$element.triggerHandler('rotateccw', _createOptions ({type: 'rotateccw', rotation:_iDelta, vector: -1, touches: null, startMove: _oDatajQueryGestures.oStartTouch, event:event_, timestamp:_oDatajQueryGestures.oStartTouch.timestamp,description: 'rotate:-1:counterclockwise'}) );1377						}1378				break;1379				}1380			}1381			_$element.triggerHandler($.jGestures.events.gestureendProcessed,event_);1382		}1383	}...jquery.jgestures.js
Source:jquery.jgestures.js  
1/**2 * jGestures: a jQuery plugin for gesture events 3 * Copyright 2010-2011, Neue Digitale / Razorfish GmbH4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 8 * Unless required by applicable law or agreed to in writing, software 9 * distributed under the License is distributed on an "AS IS" BASIS, 10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 * See the License for the specific language governing permissions and 12 * limitations under the License. 13 * 14 * @fileOverview15 * Neue Digitale / Razorfish GmbH javascript library: add touch events such as 'pinch', 16 * 'rotate', 'swipe', 'tap' and 'orientationchange' on capable user agents. 17 * For incapable devices there's a basic event substitution: a "tapone" event 18 * can be triggered by "clicking", a "swipeone" by performing a swipe-ish 19 * gesture using the mouse (buttondown - mousemove - buttonup).20 * 21 * This is still a beta version, bugfixes and improvements appreciated.22 * 23 * @author martin.krause@neue-digitale.de24 * @version 0.8725 *26 * @snvauthor				$Author: martinkr $27 * @svnversion				$Revision: 0 $28 *29 * @requires 30 * jQuery JavaScript Library v1.4.2 - http://jquery.com/31 *	Copyright 2010, John Resig32 *	Dual licensed under the MIT or GPL Version 2 licenses.33 *	http://jquery.org/license34 *35 * 36 * @copyright Neue Digitale / Razorfish GmbH37 * 38 * @example	jQuery('#swipe').bind('swipeone',eventHandler);39 *  40 * Notification on native events:41 * On every native touchstart, touchend, gesturestart and gestureend-event, 42 * jgestures triggers a corresponding custom event 43 * (jGestures.touchstart,jGestures.touchend,jGestures.gesturestart and jGestures.gestureend) on the event-element.44 * The  eventhandler's second argument represents the original touch event (yes: including all touchpoints).45 * Use this if you need very detailed control e.g. kinetic scrolling or implementing additional gestures.46 * 47 * Every jGesture-eventhandler receives a custom object as second argument 48 * containing the original event (originalEvent property) and processed 49 * information (such as delta values and timesptamp).50 * Example:{ 51 *				type: eventtype e.g. "swipe","pinch", 52				originalEvent: {DOM-Event},53*				// default: just one entry on the delta-array - the first touchpoint54*				// the first touchpoint is the reference point for every gesture, 55*				// because moving touchpoints in various directions would result in 56*				// a gesture.57*				// delta and direction details are just provided for touch not for gesture events58*				delta : [ 59*					{60*						lastX:{Number} , // x-axis: relative to the last touchevent (e.g. touchmove!)61*						lastY:{Number}, // y-axis: relative to the last touchevent (e.g. touchmove!)62*						moved: {Number},  // distance: relative to the original touchpoint 63*						startX: {Number} , // relative to the original touchpoint64*						startY: {Number} ,// relative to the original touchpoint65*					} ],66*				// based on the first touchpoint67*				direction : { // relative to the last touchevent (e.g. touchmove!)68*					vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)69*					orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)70*					lastX : {Number}, // -1,0,+1 || null (orientationchange) // relative to the last touchevent (e.g. touchmove!)71*					lastY : {Number}, // -1,0,+1 || null (orientationchange)// relative to the last touchevent (e.g. touchmove!)72*					startX: {Number} , // relative to the original touchpoint73*					startY: {Number} ,// relative to the original touchpoint74*				},75*				rotation: {Number} || {null}, // gestureonly: amount of rotation relative to the current position NOT the original 76*				scale: {Number} || {null}, // gestureonly: amount of scaling relative to the current position NOT the original 77*				duration: {Number}, // ms: relative to the original touchpoint 78*				description : {String} // details as String: {TYPE *}:{TOUCHES 1|2|3|4}:{X-AXIS 'right'|'left'|'steady'}:{Y-AXIS 'down'|'up'|'steady'} e.g. "swipe:1:left:steady" relative to the last touchpoint79*			};80 *  81 * Available jGesture-events can be grouped into: 82 *83 * 84 * Device events:85 *	The jGesture-Events in this group are triggered by the device.86 * 87 * @event 'orientationchange'88 *		The device is turned clockwise or counterclockwise. This event is triggered 89 *		by the device and might use an internal gyroscope.90 *	obj.description:91 *		orientationchange:landscape:clockwise:-9092 *		orientationchange:portrait:default:093 *		orientationchange:landscape:counterclockwise|portrait:9094 *		orientationchange:portrait:upsidedown:18095 *96 *97 * Move events:98 *	The jGesture-Events in this group are triggered during the touch/gesture 99 *	execution whenever a touchpoint changes. 100 *	In contrast to touchend/gestureend-events which are triggered after 101 *	the touch/gesture has completed. 102 *103 * @event 'pinch'104 *		Is triggered during a pinch gesture (two fingers moving away from or 105 *		towards each other).106 *	obj.description:107 *		pinch:-1:close108 *		pinch:+1:open109 * 110 * @event 'rotate'111 *		Is triggered during a rotation gesture (two fingers rotating clockwise 112 *		or counterclockwise).113 *	obj.description:114 *		rotate:-1:counterclockwise115 *		rotate:+1:+clockwise116 * 117 * @event 'swipemove'118 *		Is triggered during a swipe move gesture (finger(s) being moved around 119 *		the device, e.g. dragging)120 *	obj.description:121 *		swipemove:1:left:down122 *		swipemove:1:left:up123 *		swipemove:1:left:steady124 *		swipemove:1:right:down125 *		swipemove:1:right:up126 *		swipemove:1:right:steady127 *		swipemove:2:left:down128 *		swipemove:2:left:up129 *		swipemove:2:left:steady130 *		swipemove:2:right:down131 *		swipemove:2:right:up132 *		swipemove:2:right:steady133 *		swipemove:2:left:down134 *		swipemove:3:left:up135 *		swipemove:3:left:steady136 *		swipemove:3:right:down137 *		swipemove:3:right:up138 *		swipemove:3:right:steady139  *		swipemove:3:left:down140 *		swipemove:4:left:up141 *		swipemove:4:left:steady142 *		swipemove:4:right:down143 *		swipemove:4:right:up144 *		swipemove:4:right:steady145 *146 *  147 * Toucheend events:148 *	The jGesture-Events in this group are triggered after the touch/gesture 149 *	has completed. 150 *	In contrast to touchmove-events which are triggered during the touch/gesture 151 *	execution whenever a touchpoint changes.152 * 153 * @event 'swipeone'154 *		Is triggered after a swipe move gesture with one touchpoint (one finger155 *		was moved around the device)156 *	obj.description:157 *		swipeone:1:left:down158 *		swipeone:1:left:up159 *		swipeone:1:left:steady160 *		swipeone:1:right:down161 *		swipeone:1:right:up162 *		swipeone:1:right:steady163 * 164 * @event 'swipetwo'165 *		Is triggered after a swipe move gesture with two touchpoints (two fingers166 *		were moved around the device)167 *	obj.description:168 *		swipetwo:2:left:down169 *		swipetwo:2:left:up170 *		swipetwo:2:left:steady171 *		swipetwo:2:right:down172 *		swipetwo:2:right:up173 *		swipetwo:2:right:steady174 * 175 * @event 'swipethree'176 *		Is triggered after a swipe move gesture with three touchpoints (three 177 *		fingers were moved around the device)178 *	obj.description:179 *		swipethree:3:left:down180 *		swipethree:3:left:up181 *		swipethree:3:left:steady182 *		swipethree:3:right:down183 *		swipethree:3:right:up184 *		swipethree:3:right:steady185 * 186 * @event 'swipefour'187 *		Is triggered after a swipe move gesture with four touchpoints (four 188 *		fingers were moved around the device)189 *	obj.description:190 *		swipefour:4:left:down191 *		swipefour:4:left:up192 *		swipefour:4:left:steady193 *		swipefour:4:right:down194 *		swipefour:4:right:up195 *		swipefour:4:right:steady196 * 197  * 198 * @event 'swipeup'199 *		Is triggered after an  strict upwards swipe move gesture 200 *	obj.description:201 *		swipe:1:steady:up202 *		swipe:2:steady:up203 *		swipe:3:steady:up204 *		swipe:4:steady:up205 *206 * @event 'swiperightup'207 *		Is triggered after a rightwards and upwards swipe move gesture 208 *	obj.description:209 *		swipe:1:right:up210 *		swipe:2:right:up211 *		swipe:3:right:up212 *		swipe:4:right:up 213 * 214 * @event 'swiperight'215 *		Is triggered after a  strict rightwards swipe move gesture 216 *	obj.description:217 *		swipe:1:right:steady218 *		swipe:2:right:steady219 *		swipe:3:right:steady220 *		swipe:4:right:steady221 * 222 * @event 'swiperightdown'223 *		Is triggered after a rightwards and downwards swipe move gesture 224 *	obj.description:225 *		swipe:1:right:down226 *		swipe:2:right:down227 *		swipe:3:right:down228 *		swipe:4:right:down229 * 230 * @event 'swipedown'231 *		Is triggered after a  strict downwards swipe move gesture 232 *	obj.description:233 *		swipe:1:steady:down234 *		swipe:2:steady:down235 *		swipe:3:steady:down236 *		swipe:4:steady:down237 * 238  * @event 'swipeleftdown'239 *		Is triggered after a leftwards and downwards swipe move gesture 240 *	obj.description:241 *		swipe:1:left:down242 *		swipe:2:left:down243 *		swipe:3:left:down244 *		swipe:4:left:down245  * 246  * @event 'swipeleft'247 *		Is triggered after a strict leftwards swipe move gesture 248 *	obj.description:249 *		swipe:1:left:steady250 *		swipe:2:left:steady251 *		swipe:3:left:steady252 *		swipe:4:left:steady253   * 254  * @event 'swipeleftup'255 *		Is triggered after a leftwards and upwards swipe move gesture 256 *	obj.description:257 *		swipe:1:left:up258 *		swipe:2:left:up259 *		swipe:3:left:up260 *		swipe:4:left:up261 * 262  * @event 'tapone'263 *		Is triggered after a single (one finger) tap gesture 264 *	obj.description:265 *		tapone266* 267  * @event 'taptwo'268 *		Is triggered after a double (two finger) tap gesture 269 *	obj.description:270 *		taptwo271 * * 272  * @event 'tapthree'273 *		Is triggered after a tripple (three finger) tap gesture 274 *	obj.description:275 *		tapthree276 * 277 *  278 * Gestureend events:279 *	A gesture is an interpretation of different touchpoints. 280 *	The jGesture-Events in this group are triggered when a gesture has finished 281 *	and the touchpoints are removed from the device.282 *283 * @event 'pinchopen'284 *		Is triggered when a pinchopen gesture (two fingers moving away from each 285 *		other) occured and the touchpoints (fingers) are removed the device. 286 *	obj.description:287 *		pinch:+1:open288 * 289 * @event 'pinchclose'290 *		Is triggered when a pinchclose gesture (two fingers moving towards each 291 *		other) occured and the touchpoints (fingers) are removed the device. 292 *	obj.description:293 *		pinch:-1:close294 * 295 * @event 'rotatecw'296 *		Is triggered when a clockwise rotation gesture (two fingers rotating 297 *		clockwise) occured and the touchpoints (fingers) are removed the device.298 *	obj.description:299 *		rotate:+1:+clockwise300 * 301 * @event 'rotateccw'302 *		Is triggered when a counterclockwise rotation gesture (two fingers 303 *		rotating counterclockwise) occured and the touchpoints (fingers) are 304 *		removed the device.305 *	obj.description:306 *		rotate:-1:+counterclockwise307 * 308 * @example309 *		.bind( eventType, [ eventData ], handler(eventObject) )310 * jQuery('body').bind('tapone',function(){alert(arguments[1].description);})311  312313 */314315 (function ($) {316317     /**318     * General thresholds.319     */320     $.jGestures = {};321     $.jGestures.defaults = {};322     $.jGestures.defaults.thresholdPinchopen = 0.05;323     $.jGestures.defaults.thresholdPinchmove = 0.05;324     $.jGestures.defaults.thresholdPinch = 0.05;325     $.jGestures.defaults.thresholdPinchclose = 0.05;326     $.jGestures.defaults.thresholdRotatecw = 5; //deg327     $.jGestures.defaults.thresholdRotateccw = 5; // deg328     // a tap becomes a swipe if x/y values changes are above this threshold  329     $.jGestures.defaults.thresholdMove = 20;330     $.jGestures.defaults.thresholdSwipe = 100;331     $.jGestures.data = {};332     // get capable user agents 333     $.jGestures.data.capableDevicesInUserAgentString = ['iPad', 'iPhone', 'iPod', 'Mobile Safari']; // basic functionality such as swipe, pinch, rotate, tap should work on every mobile safari, e.g. GalaxyTab 334     $.jGestures.data.hasGestures = (function () { var _i; for (_i = 0; _i < $.jGestures.data.capableDevicesInUserAgentString.length; _i++) { if (navigator.userAgent.indexOf($.jGestures.data.capableDevicesInUserAgentString[_i]) !== -1) { return true; } } return false; })();335     $.hasGestures = $.jGestures.data.hasGestures;336     $.jGestures.events = {337         touchstart: 'jGestures.touchstart',338         touchendStart: 'jGestures.touchend;start',339         touchendProcessed: 'jGestures.touchend;processed',340         gesturestart: 'jGestures.gesturestart',341         gestureendStart: 'jGestures.gestureend;start',342         gestureendProcessed: 'jGestures.gestureend;processed'343     };344345     jQuery346		.each({347		    // "first domevent necessary"_"touch event+counter" : "exposed as"348		    // event: orientationchange349		    orientationchange_orientationchange01: "orientationchange",350		    // event: gestures351		    gestureend_pinchopen01: "pinchopen",352		    gestureend_pinchclose01: "pinchclose",353		    gestureend_rotatecw01: 'rotatecw',354		    gestureend_rotateccw01: 'rotateccw',355		    // move events356		    gesturechange_pinch01: 'pinch',357		    gesturechange_rotate01: 'rotate',358		    touchstart_swipe13: 'swipemove',359		    // event: touches360		    touchstart_swipe01: "swipeone",361		    touchstart_swipe02: "swipetwo",362		    touchstart_swipe03: "swipethree",363		    touchstart_swipe04: "swipefour",364		    touchstart_swipe05: 'swipeup',365		    touchstart_swipe06: 'swiperightup',366		    touchstart_swipe07: 'swiperight',367		    touchstart_swipe08: 'swiperightdown',368		    touchstart_swipe09: 'swipedown',369		    touchstart_swipe10: 'swipeleftdown',370		    touchstart_swipe11: 'swipeleft',371		    touchstart_swipe12: 'swipeleftup',372		    touchstart_tap01: 'tapone',373		    touchstart_tap02: 'taptwo',374		    touchstart_tap03: 'tapthree',375		    touchstart_tap04: 'tapfour'376		},377378     /**379     * Add gesture events inside the jQuery.event.special namespace 380     */381		function (sInternal_, sPublicFN_) {382383		    // add as funciton to jQuery.event.special.sPublicFN_ 384		    jQuery.event.special[sPublicFN_] = {385386		        /**387		        * When the first event handler is bound, jQuery executes the setup function.388		        * This plugin just uses one eventhandler per element, regardless of the number of bound events.389		        * All Events are stored internally as properties on the dom-element using the $.data api. 390		        * The setup-function adds the eventlistener, acting as a proxy function for the internal events.391		        * $.data.ojQueryGestures[_sDOMEvent ('tap') ] = {Boolean}392		        * @return {Void}393		        */394		        setup: function () {395396		            // split the arguments to necessary controll arguements397		            var _aSplit = sInternal_.split('_');398		            var _sDOMEvent = _aSplit[0]; // 399		            // get the associated gesture event and strip the counter: necessary for distinguisihng similliar events such as tapone-tapfour400		            var _sGestureEvent = _aSplit[1].slice(0, _aSplit[1].length - 2);401		            var _$element = jQuery(this);402		            // bind the event handler on the first $.bind() for a gestureend-event, set marker403		            if (!_$element.data('ojQueryGestures') || !_$element.data('ojQueryGestures')[_sDOMEvent]) {404		                // setup pseudo event405		                var _oDatajQueryGestures = _$element.data('ojQueryGestures') || {};406		                var oObj = {};407		                // marker for:  domEvent being set on this element 408		                // e.g.: $.data.oGestureInternals['touchstart'] = true;409		                // since they're grouped, i'm just marking the first one being added410		                oObj[_sDOMEvent] = true;411		                $.extend(true, _oDatajQueryGestures, oObj);412		                _$element.data('ojQueryGestures', _oDatajQueryGestures);413		                // add gesture events414		                if ($.hasGestures) {415		                    switch (_sGestureEvent) {416417		                        // event: orientationchange  418		                        case 'orientationchange':419		                            _$element.get(0).addEventListener('orientationchange', _onOrientationchange, false);420		                            break;421422		                        // event:   423		                        // - touchstart  424		                        // - touchmove  425		                        // - touchend  426		                        case 'tap':427		                        case 'swipe':428		                        case 'swipeup':429		                        case 'swiperightup':430		                        case 'swiperight':431		                        case 'swiperightdown':432		                        case 'swipedown':433		                        case 'swipeleftdown':434		                        case 'swipeleft':435		                            _$element.get(0).addEventListener('touchstart', _onTouchstart, false);436		                            break;437438		                        // event: gestureend  439		                        case 'pinchopen':440		                        case 'pinchclose':441		                        case 'rotatecw':442		                        case 'rotateccw':443		                            _$element.get(0).addEventListener('gesturestart', _onGesturestart, false);444		                            _$element.get(0).addEventListener('gestureend', _onGestureend, false);445		                            break;446447		                        // event: gesturechange  448		                        case 'pinch':449		                        case 'rotate':450		                            _$element.get(0).addEventListener('gesturestart', _onGesturestart, false);451		                            _$element.get(0).addEventListener('gesturechange', _onGesturechange, false);452		                            break;453		                    }454		                }455		                // create substitute for gesture events 456		                else {457		                    switch (_sGestureEvent) {458		                        // event substitutes:   459		                        // - touchstart: mousedown  460		                        // - touchmove: none  461		                        // - touchend: mouseup  462		                        case 'tap':463		                        case 'swipe':464		                            // _$element.get(0).addEventListener('mousedown', _onTouchstart, false);465		                            _$element.bind('mousedown', _onTouchstart);466		                            break;467468		                        // no substitution  469		                        case 'orientationchange':470		                        case 'pinchopen':471		                        case 'pinchclose':472		                        case 'rotatecw':473		                        case 'rotateccw':474		                        case 'pinch':475		                        case 'rotate':476477		                            break;478		                    }479		                }480481		            }482		            return false;483		        },484485		        /**486		        * For every $.bind(GESTURE) the add-function will be called.487		        * Instead of binding an actual eventlister, the event is stored as $.data on the element.488		        * The handler will be triggered using $.triggerHandler(GESTURE) if the internal 489		        * eventhandler (proxy being bound on setup()) detects a GESTURE event490		        * @param {Object} event_ jQuery-Event-Object being passed by $.bind() 491		        * @return {Void}492		        */493		        add: function (event_) {494		            // add pseudo event: properties on $.data 495		            var _$element = jQuery(this);496		            var _oDatajQueryGestures = _$element.data('ojQueryGestures');497		            //					_oDatajQueryGestures[event_.type] = { 'originalType' : event_.type , 'threshold' : event_.data.threshold, 'preventDefault' : event_.data.preventDefault } ;498		            _oDatajQueryGestures[event_.type] = { 'originalType': event_.type };499		            return false;500		        },501502		        /**503		        * For every $.unbind(GESTURE) the remove-function will be called.504		        * Instead of removing the actual eventlister, the event is removed from $.data on the element.505		        * @param {Object} event_ jQuery-Event-Object being passed by $.bind() 506		        * @return {Void}507		        */508		        remove: function (event_) {509		            // remove pseudo event: properties on $.data 510		            var _$element = jQuery(this);511		            var _oDatajQueryGestures = _$element.data('ojQueryGestures');512		            _oDatajQueryGestures[event_.type] = false;513		            _$element.data('ojQueryGestures', _oDatajQueryGestures);514		            return false;515		        },516517		        /**518		        * The last $.unbind()-call on the domElement triggers the teardown function 519		        * removing the eventlistener520		        * @return {Void}521		        */522		        // @TASK: maybe rework teardown to work with event type?!523		        teardown: function () {524		            // split the arguments to necessary controll arguements525		            var _aSplit = sInternal_.split('_');526		            var _sDOMEvent = _aSplit[0]; // 527		            // get the associated gesture event and strip the counter: necessary for distinguisihng similliar events such as tapone-tapfour528		            var _sGestureEvent = _aSplit[1].slice(0, _aSplit[1].length - 2);529		            var _$element = jQuery(this);530		            // bind the event handler on the first $.bind() for a gestureend-event, set marker531		            if (!_$element.data('ojQueryGestures') || !_$element.data('ojQueryGestures')[_sDOMEvent]) {532		                // setup pseudo event533		                var _oDatajQueryGestures = _$element.data('ojQueryGestures') || {};534		                var oObj = {};535		                // remove marker for:  domEvent being set on this element 536		                oObj[_sDOMEvent] = false;537		                $.extend(true, _oDatajQueryGestures, oObj);538		                _$element.data('ojQueryGestures', _oDatajQueryGestures);539540		                // remove gesture events541		                if ($.hasGestures) {542		                    switch (_sGestureEvent) {543544		                        // event: orientationchange  545		                        case 'orientationchange':546		                            _$element.get(0).removeEventListener('orientationchange', _onOrientationchange, false);547		                            break;548549		                        // event :   550		                        // - touchstart  551		                        // - touchmove  552		                        // - touchend  553		                        case 'tap':554		                        case 'swipe':555		                        case 'swipeup':556		                        case 'swiperightup':557		                        case 'swiperight':558		                        case 'swiperightdown':559		                        case 'swipedown':560		                        case 'swipeleftdown':561		                        case 'swipeleft':562		                        case 'swipeleftup':563		                            _$element.get(0).removeEventListener('touchstart', _onTouchstart, false);564		                            _$element.get(0).removeEventListener('touchmove', _onTouchmove, false);565		                            _$element.get(0).removeEventListener('touchend', _onTouchend, false);566		                            break;567568		                        // event: gestureend  569		                        case 'pinchopen':570		                        case 'pinchclose':571		                        case 'rotatecw':572		                        case 'rotateccw':573		                            _$element.get(0).removeEventListener('gesturestart', _onGesturestart, false);574		                            _$element.get(0).removeEventListener('gestureend', _onGestureend, false);575		                            break;576577		                        // event: gesturechange  578		                        case 'pinch':579		                        case 'rotate':580		                            _$element.get(0).removeEventListener('gesturestart', _onGesturestart, false);581		                            _$element.get(0).removeEventListener('gesturechange', _onGesturechange, false);582		                            break;583		                    }584		                }585		                // remove substitute for gesture events 586		                else {587		                    switch (_sGestureEvent) {588		                        // event substitutes:   589		                        // - touchstart: mousedown  590		                        // - touchmove: none  591		                        // - touchend: mouseup  592		                        case 'tap':593		                        case 'swipe':594		                            //									_$element.get(0).removeEventListener('mousedown', _onTouchstart, false);595		                            //									_$element.get(0).removeEventListener('mousemove', _onTouchmove, false);596		                            //									_$element.get(0).removeEventListener('mouseup', _onTouchend, false);597		                            _$element.unbind('mousedown', _onTouchstart);598		                            _$element.unbind('mousemove', _onTouchmove);599		                            _$element.unbind('mouseup', _onTouchend);600		                            break;601602		                        // no substitution  603		                        case 'orientationchange':604		                        case 'pinchopen':605		                        case 'pinchclose':606		                        case 'rotatecw':607		                        case 'rotateccw':608		                        case 'pinch':609		                        case 'rotate':610611		                            break;612		                    }613		                }614615		            }616		            return false;617		        }618619		    };620		});621622     /**623     * Creates the object that ist passed as second argument to the $element.triggerHandler function.624     * This object contains detailed informations about the gesture event.625     * @param {Object} oOptions_  {type: {String}, touches: {String}, deltaY: {String},deltaX : {String}, startMove: {Object}, event:{DOM-Event}, timestamp:{String},vector: {Number}}626     * @example _createOptions (627     *				{ 628     *					type: 'swipemove', 629     *					touches: '1', 630     *					deltaY: _iDeltaY,631     *					deltaX : _iDeltaX, 632     *					startMove: _oDatajQueryGestures.oStartTouch, 633     *					event:event_, 634     *					timestamp:_oEventData.timestamp,635     *					vector: -1636     *				}637     *			);638     * @returns {Object} 639     *			{640     *				type: eventtype e.g. "swipe","pinch",641     *				originalEvent: {DOM-Event},642     *				// default: just one entry on the delta-array - the first touchpoint643     *				// the first touchpoint is the reference point for every gesture, 644     *				// because moving touchpoints in various directions would result in 645     *				// a gesture.646     *				// delta and direction details are just provided for touch not for gesture events647     *				delta : [ 648     *					{649     *						lastX:{Number} , // x-axis: relative to the last touchevent (e.g. touchmove!)650     *						lastY:{Number}, // y-axis: relative to the last touchevent (e.g. touchmove!)651     *						moved: {Number},  // distance: relative to the original touchpoint 652     *						startX: {Number} , // relative to the original touchpoint653     *						startY: {Number} ,// relative to the original touchpoint654     *					} ],655     *				// based on the first touchpoint656     *				direction : { // relative to the last touchevent (e.g. touchmove!)657     *					vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)658     *					orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)659     *					lastX : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)660     *					lastY : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)661     *					startX: {Number} , //-1,0,+1 relative to the original touchpoint662     *					startY: {Number} ,// -1,0,+1 relative to the original touchpoint663     *				},664     *				rotation: {Number} || {null}, // gestureonly: amount of rotation relative to the current position NOT the original 665     *				scale: {Number} || {null}, // gestureonly: amount of scaling relative to the current position NOT the original 666     *				duration: {Number}, // ms: relative to the original touchpoint 667     *				description : {String} // details as String: {TYPE *}:{TOUCHES 1|2|3|4}:{X-AXIS 'right'|'left'|'steady'}:{Y-AXIS 'down'|'up'|'steady'} e.g. "swipe:1:left:steady" relative to the last touchpoint668     *			};669     */670     function _createOptions(oOptions_) {671         // force properties672         oOptions_.startMove = (oOptions_.startMove) ? oOptions_.startMove : { startX: null, startY: null, timestamp: null };673         var _iNow = new Date().getTime();674675         // calculate touch differences 676         if (oOptions_.touches) {677             // store delta values678             var _oDelta = [679				{680				    lastX: oOptions_.deltaX,681				    lastY: oOptions_.deltaY,682				    moved: null,683				    startX: oOptions_.screenX - oOptions_.startMove.screenX,684				    startY: oOptions_.screenY - oOptions_.startMove.screenY685				}686			];687688             var _oDirection = {689                 vector: oOptions_.vector,690                 orientation: window.orientation || null,691                 lastX: ((_oDelta[0].lastX > 0) ? +1 : ((_oDelta[0].lastX < 0) ? -1 : 0)),692                 lastY: ((_oDelta[0].lastY > 0) ? +1 : ((_oDelta[0].lastY < 0) ? -1 : 0)),693                 startX: ((_oDelta[0].startX > 0) ? +1 : ((_oDelta[0].startX < 0) ? -1 : 0)),694                 startY: ((_oDelta[0].startY > 0) ? +1 : ((_oDelta[0].startY < 0) ? -1 : 0))695             };696697             // calculate distance traveled using the pythagorean theorem		698             _oDelta[0].moved = Math.sqrt(Math.pow(Math.abs(_oDelta[0].startX), 2) + Math.pow(Math.abs(_oDelta[0].startY), 2));699700         }701         return {702             type: oOptions_.type || null,703             originalEvent: oOptions_.event || null,704             delta: _oDelta || null,705             direction: _oDirection || { orientation: window.orientation || null, vector: oOptions_.vector || null },706             duration: (oOptions_.startMove.timestamp) ? _iNow - oOptions_.timestamp : null,707             rotation: oOptions_.rotation || null,708             scale: oOptions_.scale || null,709             description: oOptions_.description || [710				oOptions_.type,711				':',712				oOptions_.touches,713				':',714				((_oDelta[0].lastX != 0) ? ((_oDelta[0].lastX > 0) ? 'right' : 'left') : 'steady'),715				':',716				((_oDelta[0].lastY != 0) ? ((_oDelta[0].lastY > 0) ? 'down' : 'up') : 'steady')717				].join('')718         };719720     }721722723724     /**725     * DOM-event handlers726     */727728     /**729     * Handler: orientationchange730     * Triggers the bound orientationchange handler on the window element731     * The "orientationchange" handler will receive an object with additional information732     * about the event.733     *  {734     * 	direction : {735     * 		orientation: {-90|0|90|180}736     * 	},737     * 	description : [738     * 		'orientationchange:{landscape:clockwise:|portrait:default|landscape:counterclockwise|portrait:upsidedown}:{-90|0|90|180}' // e.g. 'orientation:landscape:clockwise:-90739     * 	}740     * @param {DOM-Event} event_741     * @return {Void}742     */743     function _onOrientationchange(event_) {744745         // window.orientation: -90,0,90,180746         var _aDict = ['landscape:clockwise:', 'portrait:default:', 'landscape:counterclockwise:', 'portrait:upsidedown:'];747748         $(window).triggerHandler('orientationchange',749			{750			    direction: { orientation: window.orientation },751			    description: [752					'orientationchange:',753					_aDict[((window.orientation / 90) + 1)],754					window.orientation755					].join('')756			});757     }758759760     /**761     * Handler: touchstart or mousedown762     * Setup pseudo-event by storing initial values such as :763     *		screenX : {Number}764     *	screenY : {Number}765     *	timestamp: {Number}766     *  on the pseudo gesture event and 767     *  sets up additional eventlisteners for handling touchmove events.768     * @param {DOM-Event} event_769     * @return {Void}770     */771     function _onTouchstart(event_) {772773         // ignore bubbled handlers774         // if ( event_.currentTarget !== event_.target ) { return; }775776         var _$element = jQuery(event_.currentTarget);777         // var _$element = jQuery(event_.target); 778779         // trigger custom notification780         _$element.triggerHandler($.jGestures.events.touchstart, event_);781782783         // set the necessary touch events784         if ($.hasGestures) {785             event_.currentTarget.addEventListener('touchmove', _onTouchmove, false);786             event_.currentTarget.addEventListener('touchend', _onTouchend, false);787         }788         // event substitution789         else {790             //			event_.currentTarget.addEventListener('mousemove', _onTouchmove, false);791             //			event_.currentTarget.addEventListener('mouseup', _onTouchend, false);792             _$element.bind('mousemove', _onTouchmove);793             _$element.bind('mouseup', _onTouchend);794         }795796         // get stored pseudo event797         var _oDatajQueryGestures = _$element.data('ojQueryGestures');798799         // var _oEventData = _oDatajQueryGestures[_sType];800         var _eventBase = (event_.touches) ? event_.touches[0] : event_;801         // store current values for calculating relative values (changes between touchmoveevents)802         var _oObj = {};803         _oObj.oLastSwipemove = { screenX: _eventBase.screenX, screenY: _eventBase.screenY, timestamp: new Date().getTime() };804         _oObj.oStartTouch = { screenX: _eventBase.screenX, screenY: _eventBase.screenY, timestamp: new Date().getTime() };805806         _$element.data('ojQueryGestures', $.extend(true, _oDatajQueryGestures, _oObj));807     }808809810     /**811     * Handler: touchmove or mousemove812     * Calculates the x/y changes since the last event, 813     * compares it to $.jGestures.defaults.thresholdMove and triggers 814     * an swipemove event if the distance exceed the 815     * threshold.816     * Custom-event argument object: 817     * {Object} 818     *			{819     *				type: e.g. 'swipemove',820     *				â: {DOM-Event},821     *				// default: just one entry on the delta-array - the first touchpoint822     *				// the first touchpoint is the reference point for every gesture, 823     *				// because moving touchpoints in various directions would result in 824     *				// a gesture.825     *				// delta and direction details are just provided for touch not for gesture events826     *				delta : [ 827     *					{828     *						lastX:{Number} , // x-axis: relative to the last touchevent (e.g. touchmove!)829     *						lastY:{Number}, // y-axis: relative to the last touchevent (e.g. touchmove!)830     *						moved: {Number},  // distance: relative to the original touchpoint 831     *						startX: {Number} , // relative to the original touchpoint832     *						startY: {Number} ,// relative to the original touchpoint833     *					} ],834     *				// based on the first touchpoint835     *				direction : { // relative to the last touchevent (e.g. touchmove!)836     *					vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)837     *					orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)838     *					lastX : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)839     *					lastY : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)840     *					startX: {Number} , //-1,0,+1 relative to the original touchpoint841     *					startY: {Number} ,// -1,0,+1 relative to the original touchpoint842     *				},843     *				rotation: {null}, // gestureonly: amount of rotation relative to the current position NOT the original 844     *				scale: {null}, // gestureonly: amount of scaling relative to the current position NOT the original 845     *				duration: {Number}, // ms: relative to the original touchpoint 846     *				description : {String} // details as String: {TYPE *}:{TOUCHES 1|2|3|4}:{X-AXIS 'right'|'left'|'steady'}:{Y-AXIS 'down'|'up'|'steady'} e.g. "swipe:1:left:steady" relative to the last touchpoint847     *			};848     *		description : {String} // details as String: swipemove:1:{X-AXIS 'right'|'left'|'steady'}:{Y-AXIS 'down'|'up'|'steady'} e.g. "swipemove:1:left:steady"849     *	};850     * @param {DOM-Event} event_851     * @return {Void}852     */853     function _onTouchmove(event_) {854855         var _$element = jQuery(event_.currentTarget);856         // var _$element = jQuery(event_.target); 857858         // get stored pseudo event859         var _oDatajQueryGestures = _$element.data('ojQueryGestures');860861         var _bHasTouches = !!event_.touches;862         var _iScreenX = (_bHasTouches) ? event_.changedTouches[0].screenX : event_.screenX;863         var _iScreenY = (_bHasTouches) ? event_.changedTouches[0].screenY : event_.screenY;864865         //relative to the last event866         var _oEventData = _oDatajQueryGestures.oLastSwipemove;867         var _iDeltaX = _iScreenX - _oEventData.screenX;868         var _iDeltaY = _iScreenY - _oEventData.screenY;869870         // there's a swipemove set (not the first occurance), trigger event 871         if (!!_oDatajQueryGestures.oLastSwipemove) {872             // check 873             var _oDetails = _createOptions({ type: 'swipemove', touches: (_bHasTouches) ? event_.touches.length : '1', screenY: _iScreenY, screenX: _iScreenX, deltaY: _iDeltaY, deltaX: _iDeltaX, startMove: _oEventData, event: event_, timestamp: _oEventData.timestamp });874             _$element.triggerHandler(_oDetails.type, _oDetails);875         }876         // store the new values877         var _oObj = {};878         var _eventBase = (event_.touches) ? event_.touches[0] : event_;879         _oObj.oLastSwipemove = { screenX: _eventBase.screenX, screenY: _eventBase.screenY, timestamp: new Date().getTime() };880         _$element.data('ojQueryGestures', $.extend(true, _oDatajQueryGestures, _oObj));881     }882883884     /**885     * Handler: touchend or mouseup886     * Removes the additional handlers (move/end)887     * Calculates the x/y changes since the touchstart event888     * not in relation to the last move event.889     * Triggers the  890     *	swipeone|swipetwo|swipethree|swipefour|891     *	swipeup|swiperightup|swiperight|swiperightdown|swipedown|892     *	swipeleftdown|swipeleft|swipeleftup|893     *	tapone|taptwo|tapthree|tapfour 894     * event.895     *		{Object} 896     *			{897     *				type: eventtype e.g. "swipeone","swipeleftdown",898     *				originalEvent: {DOM-Event},899     *				// default: just one entry on the delta-array - the first touchpoint900     *				// the first touchpoint is the reference point for every gesture, 901     *				// because moving touchpoints in various directions would result in 902     *				// a gesture.903     *				// delta and direction details are just provided for touch not for gesture events904     *				delta : [ 905     *					{906     *						lastX:{Number} , // x-axis: relative to the last touchevent (e.g. touchmove!)907     *						lastY:{Number}, // y-axis: relative to the last touchevent (e.g. touchmove!)908     *						moved: {Number},  // distance: relative to the original touchpoint 909     *						startX: {Number} , // relative to the original touchpoint910     *						startY: {Number} ,// relative to the original touchpoint911     *					} ],912     *				// based on the first touchpoint913     *				direction : { // relative to the last touchevent (e.g. touchmove!)914     *					vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)915     *					orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)916     *					lastX : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)917     *					lastY : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)918     *					startX: {Number} , //-1,0,+1 relative to the original touchpoint919     *					startY: {Number} ,// -1,0,+1 relative to the original touchpoint920     *				},921     *				rotation: {null}, 922     *				scale: {null} , 923     *				duration: {Number}, // ms: relative to the original touchpoint 924     *				description : {String} // details as String: {TYPE *}:{TOUCHES 1|2|3|4}:{X-AXIS 'right'|'left'|'steady'}:{Y-AXIS 'down'|'up'|'steady'} e.g. "swipe:1:left:steady" relative to the last touchpoint925     *			};926     * @param {DOM-Event} event_927     * @return {Void}928     */929     function _onTouchend(event_) {930931         // ignore bubbled handlers932         // if ( event_.currentTarget !== event_.target ) { return; }933934         var _$element = jQuery(event_.currentTarget);935         var _bHasTouches = !!event_.changedTouches;936         var _iTouches = (_bHasTouches) ? event_.changedTouches.length : '1';937         var _iScreenX = (_bHasTouches) ? event_.changedTouches[0].screenX : event_.screenX;938         var _iScreenY = (_bHasTouches) ? event_.changedTouches[0].screenY : event_.screenY;939940         // trigger custom notification941         _$element.triggerHandler($.jGestures.events.touchendStart, event_);942943         // var _$element = jQuery(event_.target); 944         // remove events945         if ($.hasGestures) {946             event_.currentTarget.removeEventListener('touchmove', _onTouchmove, false);947             event_.currentTarget.removeEventListener('touchend', _onTouchend, false);948         }949         // event substitution950         else {951             //			event_.currentTarget.removeEventListener('mousemove', _onTouchmove, false);952             //			event_.currentTarget.removeEventListener('mouseup', _onTouchend, false);953             _$element.unbind('mousemove', _onTouchmove);954             _$element.unbind('mouseup', _onTouchend);955         }956         // get all bound pseudo events957         var _oDatajQueryGestures = _$element.data('ojQueryGestures');958959         // if the current change on the x/y position is above the defined threshold for moving an element set the moved flag 960         // to distinguish between a moving gesture and a shaking finger trying to tap961         var _bHasMoved = (962			Math.abs(_oDatajQueryGestures.oStartTouch.screenX - _iScreenX) > $.jGestures.defaults.thresholdMove ||963			Math.abs(_oDatajQueryGestures.oStartTouch.screenY - _iScreenY) > $.jGestures.defaults.thresholdMove964		) ? true : false;965966         // if the current change on the x/y position is above the defined threshold for swiping set the moved flag 967         // to indicate we're dealing with a swipe gesture968         var _bHasSwipeGesture = (969			Math.abs(_oDatajQueryGestures.oStartTouch.screenX - _iScreenX) > $.jGestures.defaults.thresholdSwipe ||970			Math.abs(_oDatajQueryGestures.oStartTouch.screenY - _iScreenY) > $.jGestures.defaults.thresholdSwipe971		) ? true : false;972973974         var _sType;975         // trigger events for all bound pseudo events on this element 976         for (_sType in _oDatajQueryGestures) {977978             // get current pseudo event979             var _oEventData = _oDatajQueryGestures.oStartTouch;980981             var _oDelta = {};982             var _iScreenX = (_bHasTouches) ? event_.changedTouches[0].screenX : event_.screenX;983             var _iScreenY = (_bHasTouches) ? event_.changedTouches[0].screenY : event_.screenY;984             // calculate distances in relation to the touchstart position not the last touchmove event!985             var _iDeltaX = _iScreenX - _oEventData.screenX;986             var _iDeltaY = _iScreenY - _oEventData.screenY;987             var _oDetails = _createOptions({ type: 'swipe', touches: _iTouches, screenY: _iScreenY, screenX: _iScreenX, deltaY: _iDeltaY, deltaX: _iDeltaX, startMove: _oEventData, event: event_, timestamp: _oEventData.timestamp });988989             var _aDict = ['zero', 'one', 'two', 'three', 'four'];990991             // swipe marker992             var _bIsSwipe = false;993994             // trigger bound events on this element995             switch (_sType) {996                 case 'swipeone':997998                     if (_bHasTouches === false && _iTouches == 1 && _bHasMoved === false) {999                         // trigger tapone!1000                         break;1001                     }1002                     if (_bHasTouches === false || (_iTouches == 1 && _bHasMoved === true && _bHasSwipeGesture === true)) {1003                         _bIsSwipe = true;10041005                         _oDetails.type = ['swipe', _aDict[_iTouches]].join('');1006                         _$element.triggerHandler(_oDetails.type, _oDetails);1007                     }1008                     break;10091010                 case 'swipetwo':1011                     if ((_bHasTouches && _iTouches == 2 && _bHasMoved === true && _bHasSwipeGesture === true)) {1012                         _bIsSwipe = true;1013                         _oDetails.type = ['swipe', _aDict[_iTouches]].join('');1014                         _$element.triggerHandler(_oDetails.type, _oDetails);1015                     }1016                     break;10171018                 case 'swipethree':1019                     if ((_bHasTouches && _iTouches == 3 && _bHasMoved === true && _bHasSwipeGesture === true)) {1020                         _bIsSwipe = true;1021                         _oDetails.type = ['swipe', _aDict[_iTouches]].join('');1022                         _$element.triggerHandler(_oDetails.type, _oDetails);1023                     }1024                     break;10251026                 case 'swipefour':1027                     if ((_bHasTouches && _iTouches == 4 && _bHasMoved === true && _bHasSwipeGesture === true)) {1028                         _bIsSwipe = true;1029                         _oDetails.type = ['swipe', _aDict[_iTouches]].join('');1030                         _$element.triggerHandler(_oDetails.type, _oDetails);1031                     }1032                     break;10331034                 case 'swipeup':1035                 case 'swiperightup':1036                 case 'swiperight':1037                 case 'swiperightdown':1038                 case 'swipedown':1039                 case 'swipeleftdown':1040                 case 'swipeleft':1041                 case 'swipeleftup':1042                     if (_bHasTouches && _bHasMoved === true && _bHasSwipeGesture === true) {1043                         _bIsSwipe = true;1044                         _oDetails.type = [1045									'swipe',1046								((_oDetails.delta[0].lastX != 0) ? ((_oDetails.delta[0].lastX > 0) ? 'right' : 'left') : ''),1047								((_oDetails.delta[0].lastY != 0) ? ((_oDetails.delta[0].lastY > 0) ? 'down' : 'up') : '')1048									].join('');1049                         if (_sType == _oDetails.type) {1050                             _$element.triggerHandler(_oDetails.type, _oDetails);1051                         }1052                     }1053                     break;10541055                 case 'tapone':1056                 case 'taptwo':1057                 case 'tapthree':1058                 case 'tapfour':1059                     if (( /* _bHasTouches && */_bHasMoved !== true && _bIsSwipe !== true) && (_aDict[_iTouches] == _sType.slice(3))) {1060                         _oDetails.description = ['tap', _aDict[_iTouches]].join('');1061                         _oDetails.type = ['tap', _aDict[_iTouches]].join('');1062                         _$element.triggerHandler(_oDetails.type, _oDetails);1063                     }1064                     break;10651066             }10671068             // refresh pseudo events1069             var _oObj = {};1070             //			_oObj[_sType] = false;1071             //			_oObj.hasTouchmoved = false;1072             _$element.data('ojQueryGestures', $.extend(true, _oDatajQueryGestures, _oObj));1073             _$element.data('ojQueryGestures', $.extend(true, _oDatajQueryGestures, _oObj));10741075         }1076         _$element.triggerHandler($.jGestures.events.touchendProcessed, event_);1077     }107810791080     /**1081     * Handler: gesturestart1082     * Setup pseudo-event by storing initial values such as :1083     *	timestamp: {Number}1084     *  on the pseudo gesture event1085     * Since the gesture-event doesn't supply event.touches no tuchpoints will be calculated 1086     * @param {DOM-Event} event_1087     * @return {Void}1088     */1089     function _onGesturestart(event_) {10901091         // ignore bubbled handlers1092         // if ( event_.currentTarget !== event_.target ) { return; }10931094         var _$element = jQuery(event_.currentTarget);1095         // var _$element = jQuery(event_.target); 10961097         // trigger custom notification1098         _$element.triggerHandler($.jGestures.events.gesturestart, event_);109911001101         // get stored pseudo event1102         var _oDatajQueryGestures = _$element.data('ojQueryGestures');11031104         // var _oEventData = _oDatajQueryGestures[_sType];1105         // store current values for calculating relative values (changes between touchmoveevents)1106         var _oObj = {};1107         _oObj.oStartTouch = { timestamp: new Date().getTime() };1108         _$element.data('ojQueryGestures', $.extend(true, _oDatajQueryGestures, _oObj));1109     }11101111     /**1112     * Handler: gesturechange1113     * Read the event_.scale / event_.rotate values,1114     * an triggers a pinch|rotate event if necessary.1115     * Since the gesture-event doesn't supply event.touches no tuchpoints will be calculated1116     * @returns {Object} 1117     *			{1118     *				type: eventtype e.g. "pinch","rotate",1119     *				originalEvent: {DOM-Event},1120     *				// delta and direction details are just provided for touch not for gesture events1121     *				delta : null,1122     *				direction :null,1123     *				vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)1124     *				orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)1125     *				rotation: {Number} , //  amount of rotation relative to the current position NOT the original 1126     *				scale: {Number} , // amount of scaling relative to the current position NOT the original 1127     *				duration: {Number}, // ms: relative to the original touchpoint 1128     *				description : {String} // details as String: pinch:{'close'|'open'} e.g. "pinch:-1:close" ||  rotate:{'counterclockwise'|'clockwise'} e.g. "rotate:-1:counterclockwise"1129     *			};1130     * @param {DOM-Event} event_1131     * @return {Void}1132     */1133     function _onGesturechange(event_) {11341135         // ignore bubbled handlers1136         // if ( event_.currentTarget !== event_.target ) { return; }11371138         var _$element = jQuery(event_.currentTarget);1139         // var _$element = jQuery(event_.target); 1140         var _iDelta, _iDirection, _sDesc, _oDetails;1141         // get all pseudo events1142         var _oDatajQueryGestures = _$element.data('ojQueryGestures');11431144         // trigger events for all bound pseudo events on this element1145         var _sType;1146         for (_sType in _oDatajQueryGestures) {11471148             // trigger a specific bound event1149             switch (_sType) {11501151                 case 'pinch':1152                     _iDelta = event_.scale;1153                     if (((_iDelta < 1) && (_iDelta % 1) < (1 - $.jGestures.defaults.thresholdPinchclose)) || ((_iDelta > 1) && (_iDelta % 1) > ($.jGestures.defaults.thresholdPinchopen))) {1154                         _iDirection = (_iDelta < 1) ? -1 : +1;1155                         _oDetails = _createOptions({ type: 'pinch', scale: _iDelta, touches: null, startMove: _oDatajQueryGestures.oStartTouch, event: event_, timestamp: _oDatajQueryGestures.oStartTouch.timestamp, vector: _iDirection, description: ['pinch:', _iDirection, ':', ((_iDelta < 1) ? 'close' : 'open')].join('') });1156                         _$element.triggerHandler(_oDetails.type, _oDetails);1157                     }1158                     break;11591160                 case 'rotate':1161                     _iDelta = event_.rotation;1162                     if (((_iDelta < 1) && (-1 * (_iDelta) > $.jGestures.defaults.thresholdRotateccw)) || ((_iDelta > 1) && (_iDelta > $.jGestures.defaults.thresholdRotatecw))) {1163                         _iDirection = (_iDelta < 1) ? -1 : +1;1164                         _oDetails = _createOptions({ type: 'rotate', rotation: _iDelta, touches: null, startMove: _oDatajQueryGestures.oStartTouch, event: event_, timestamp: _oDatajQueryGestures.oStartTouch.timestamp, vector: _iDirection, description: ['rotate:', _iDirection, ':', ((_iDelta < 1) ? 'counterclockwise' : 'clockwise')].join('') });1165                         _$element.triggerHandler(_oDetails.type, _oDetails);1166                     }1167                     break;11681169             }1170         }11711172     }117311741175     /**1176     * Handler: gestureend1177     * Read the event_.scale / event_.rotate values,1178     * compares it to $.jGestures.defaults.threshold* and triggers 1179     * a pinchclose|pinchclose|rotatecw|rotateccw event if the distance exceed the 1180     * Since the gesture-event doesn't supply event.touches no tuchpoints will be calculated1181     * * Custom-event argument object: 1182     * @returns {Object} 1183     *			{1184     *				type: eventtype e.g. "pinchclose","pinchopen", "rotatecw", "rotateccw",1185     *				originalEvent: {DOM-Event},1186     *				// delta and direction details are just provided for touch not for gesture events1187     *				delta : null,1188     *				// based on the first touchpoint1189     *				direction : null // relative to the last touchevent (e.g. touchmove!)1190     *				vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)1191     *				orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)1192     *				rotation: {Number} , //  amount of rotation relative to the current position NOT the original 1193     *				scale: {Number} , // amount of scaling relative to the current position NOT the original 1194     *				duration: {Number}, // ms: relative to the original touchpoint 1195     *				description : {String} // details as String: pinch:{'close'|'open'} e.g. "pinch:-1:close" ||  rotate:{'counterclockwise'|'clockwise'} e.g. "rotate:-1:counterclockwise"1196     *			};1197     * @param {DOM-Event} event_1198     * @return {Void}1199     */1200     function _onGestureend(event_) {1201         // ignore bubbled handlers1202         // if ( event_.currentTarget !== event_.target ) { return; }12031204         var _$element = jQuery(event_.currentTarget);1205         // var _$element = jQuery(event_.target);12061207         // trigger custom notification1208         _$element.triggerHandler($.jGestures.events.gestureendStart, event_);12091210         var _iDelta;1211         var _oDatajQueryGestures = _$element.data('ojQueryGestures');12121213         // trigger handler for every bound event1214         var _sType;1215         for (_sType in _oDatajQueryGestures) {12161217             switch (_sType) {12181219                 case 'pinchclose':1220                     _iDelta = event_.scale;1221                     if ((_iDelta < 1) && (_iDelta % 1) < (1 - $.jGestures.defaults.thresholdPinchclose)) {1222                         _$element.triggerHandler('pinchclose', _createOptions({ type: 'pinchclose', scale: _iDelta, vector: -1, touches: null, startMove: _oDatajQueryGestures.oStartTouch, event: event_, timestamp: _oDatajQueryGestures.oStartTouch.timestamp, description: 'pinch:-1:close' }));1223                     }1224                     break;12251226                 case 'pinchopen':1227                     _iDelta = event_.scale;1228                     if ((_iDelta > 1) && (_iDelta % 1) > ($.jGestures.defaults.thresholdPinchopen)) {1229                         _$element.triggerHandler('pinchopen', _createOptions({ type: 'pinchopen', scale: _iDelta, vector: +1, touches: null, startMove: _oDatajQueryGestures.oStartTouch, event: event_, timestamp: _oDatajQueryGestures.oStartTouch.timestamp, description: 'pinch:+1:open' }));1230                     }1231                     break;12321233                 case 'rotatecw':1234                     _iDelta = event_.rotation;1235                     if ((_iDelta > 1) && (_iDelta > $.jGestures.defaults.thresholdRotatecw)) {1236                         _$element.triggerHandler('rotatecw', _createOptions({ type: 'rotatecw', rotation: _iDelta, vector: +1, touches: null, startMove: _oDatajQueryGestures.oStartTouch, event: event_, timestamp: _oDatajQueryGestures.oStartTouch.timestamp, description: 'rotate:+1:clockwise' }));1237                     }1238                     break;12391240                 case 'rotateccw':1241                     _iDelta = event_.rotation;1242                     if ((_iDelta < 1) && (-1 * (_iDelta) > $.jGestures.defaults.thresholdRotateccw)) {1243                         _$element.triggerHandler('rotateccw', _createOptions({ type: 'rotateccw', rotation: _iDelta, vector: -1, touches: null, startMove: _oDatajQueryGestures.oStartTouch, event: event_, timestamp: _oDatajQueryGestures.oStartTouch.timestamp, description: 'rotate:-1:counterclockwise' }));1244                     }1245                     break;12461247             }1248         }1249         _$element.triggerHandler($.jGestures.events.gestureendProcessed, event_);1250     }1251 }
...jgestures.js
Source:jgestures.js  
1/**2 * jGestures: a jQuery plugin for gesture events3 * Copyright 2010-2011 Neue Digitale / Razorfish GmbH4 * Copyright 2011-2012, Razorfish GmbH5 * Licensed under the Apache License, Version 2.0 (the "License");6 * you may not use this file except in compliance with the License.7 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.08 * Unless required by applicable law or agreed to in writing, software9 * distributed under the License is distributed on an "AS IS" BASIS,10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11 * See the License for the specific language governing permissions and12 * limitations under the License.13 * @copyright Razorfish GmbH14 * @author martin.krause@razorfish.de15 * @version 0.90-shake16 * @requires jQuery JavaScript Library v1.4.2 - http://jquery.com/- Copyright 2010, John Resig- Dual licensed under the MIT or GPL Version 2 licenses. http://jquery.org/license17 */18(function(c) {19    c.jGestures = {};20    c.jGestures.defaults = {};21    c.jGestures.defaults.thresholdShake = {22        requiredShakes: 10,23        freezeShakes: 100,24        frontback: {25            sensitivity: 1026        },27        leftright: {28            sensitivity: 1029        },30        updown: {31            sensitivity: 1032        }33    };34    c.jGestures.defaults.thresholdPinchopen = 0.05;35    c.jGestures.defaults.thresholdPinchmove = 0.05;36    c.jGestures.defaults.thresholdPinch = 0.05;37    c.jGestures.defaults.thresholdPinchclose = 0.05;38    c.jGestures.defaults.thresholdRotatecw = 5;39    c.jGestures.defaults.thresholdRotateccw = 5;40    c.jGestures.defaults.thresholdMove = 20;41    c.jGestures.defaults.thresholdSwipe = 100;42    c.jGestures.data = {};43    c.jGestures.data.capableDevicesInUserAgentString = ["iPad", "iPhone", "iPod", "Mobile Safari"];44    c.jGestures.data.hasGestures = (function() {45        var k;46        for (k = 0; k < c.jGestures.data.capableDevicesInUserAgentString.length; k++) {47            if (navigator.userAgent.indexOf(c.jGestures.data.capableDevicesInUserAgentString[k]) !== -1) {48                return true49            }50        }51        return false52    })();53    c.hasGestures = c.jGestures.data.hasGestures;54    c.jGestures.events = {55        touchstart: "jGestures.touchstart",56        touchendStart: "jGestures.touchend;start",57        touchendProcessed: "jGestures.touchend;processed",58        gesturestart: "jGestures.gesturestart",59        gestureendStart: "jGestures.gestureend;start",60        gestureendProcessed: "jGestures.gestureend;processed"61    };62    jQuery.each({63        orientationchange_orientationchange01: "orientationchange",64        gestureend_pinchopen01: "pinchopen",65        gestureend_pinchclose01: "pinchclose",66        gestureend_rotatecw01: "rotatecw",67        gestureend_rotateccw01: "rotateccw",68        gesturechange_pinch01: "pinch",69        gesturechange_rotate01: "rotate",70        touchstart_swipe13: "swipemove",71        touchstart_swipe01: "swipeone",72        touchstart_swipe02: "swipetwo",73        touchstart_swipe03: "swipethree",74        touchstart_swipe04: "swipefour",75        touchstart_swipe05: "swipeup",76        touchstart_swipe06: "swiperightup",77        touchstart_swipe07: "swiperight",78        touchstart_swipe08: "swiperightdown",79        touchstart_swipe09: "swipedown",80        touchstart_swipe10: "swipeleftdown",81        touchstart_swipe11: "swipeleft",82        touchstart_swipe12: "swipeleftup",83        touchstart_tap01: "tapone",84        touchstart_tap02: "taptwo",85        touchstart_tap03: "tapthree",86        touchstart_tap04: "tapfour",87        devicemotion_shake01: "shake",88        devicemotion_shake02: "shakefrontback",89        devicemotion_shake03: "shakeleftright",90        devicemotion_shake04: "shakeupdown"91    },92    function(l, k) {93        jQuery.event.special[k] = {94            setup: function() {95                var r = l.split("_");96                var o = r[0];97                var m = r[1].slice(0, r[1].length - 2);98                var p = jQuery(this);99                var q;100                var n;101                if (!p.data("ojQueryGestures") || !p.data("ojQueryGestures")[o]) {102                    q = p.data("ojQueryGestures") || {};103                    n = {};104                    n[o] = true;105                    c.extend(true, q, n);106                    p.data("ojQueryGestures", q);107                    if (c.hasGestures) {108                        switch (m) {109                        case "orientationchange":110                            p.get(0).addEventListener("orientationchange", a, false);111                            break;112                        case "shake":113                        case "shakefrontback":114                        case "shakeleftright":115                        case "shakeupdown":116                        case "tilt":117                            p.get(0).addEventListener("devicemotion", b, false);118                            break;119                        case "tap":120                        case "swipe":121                        case "swipeup":122                        case "swiperightup":123                        case "swiperight":124                        case "swiperightdown":125                        case "swipedown":126                        case "swipeleftdown":127                        case "swipeleft":128                            p.get(0).addEventListener("touchstart", h, false);129                            break;130                        case "pinchopen":131                        case "pinchclose":132                        case "rotatecw":133                        case "rotateccw":134                            p.get(0).addEventListener("gesturestart", e, false);135                            p.get(0).addEventListener("gestureend", i, false);136                            break;137                        case "pinch":138                        case "rotate":139                            p.get(0).addEventListener("gesturestart", e, false);140                            p.get(0).addEventListener("gesturechange", f, false);141                            break142                        }143                    } else {144                        switch (m) {145                        case "tap":146                        case "swipe":147                            p.bind("mousedown", h);148                            break;149                        case "orientationchange":150                        case "pinchopen":151                        case "pinchclose":152                        case "rotatecw":153                        case "rotateccw":154                        case "pinch":155                        case "rotate":156                        case "shake":157                        case "tilt":158                            break159                        }160                    }161                }162                return false163            },164            add: function(n) {165                var m = jQuery(this);166                var o = m.data("ojQueryGestures");167                o[n.type] = {168                    originalType: n.type169                };170                return false171            },172            remove: function(n) {173                var m = jQuery(this);174                var o = m.data("ojQueryGestures");175                o[n.type] = false;176                m.data("ojQueryGestures", o);177                return false178            },179            teardown: function() {180                var r = l.split("_");181                var o = r[0];182                var m = r[1].slice(0, r[1].length - 2);183                var p = jQuery(this);184                var q;185                var n;186                if (!p.data("ojQueryGestures") || !p.data("ojQueryGestures")[o]) {187                    q = p.data("ojQueryGestures") || {};188                    n = {};189                    n[o] = false;190                    c.extend(true, q, n);191                    p.data("ojQueryGestures", q);192                    if (c.hasGestures) {193                        switch (m) {194                        case "orientationchange":195                            p.get(0).removeEventListener("orientationchange", a, false);196                            break;197                        case "shake":198                        case "shakefrontback":199                        case "shakeleftright":200                        case "shakeupdown":201                        case "tilt":202                            p.get(0).removeEventListener("devicemotion", b, false);203                            break;204                        case "tap":205                        case "swipe":206                        case "swipeup":207                        case "swiperightup":208                        case "swiperight":209                        case "swiperightdown":210                        case "swipedown":211                        case "swipeleftdown":212                        case "swipeleft":213                        case "swipeleftup":214                            p.get(0).removeEventListener("touchstart", h, false);215                            p.get(0).removeEventListener("touchmove", g, false);216                            p.get(0).removeEventListener("touchend", j, false);217                            break;218                        case "pinchopen":219                        case "pinchclose":220                        case "rotatecw":221                        case "rotateccw":222                            p.get(0).removeEventListener("gesturestart", e, false);223                            p.get(0).removeEventListener("gestureend", i, false);224                            break;225                        case "pinch":226                        case "rotate":227                            p.get(0).removeEventListener("gesturestart", e, false);228                            p.get(0).removeEventListener("gesturechange", f, false);229                            break230                        }231                    } else {232                        switch (m) {233                        case "tap":234                        case "swipe":235                            p.unbind("mousedown", h);236                            p.unbind("mousemove", g);237                            p.unbind("mouseup", j);238                            break;239                        case "orientationchange":240                        case "pinchopen":241                        case "pinchclose":242                        case "rotatecw":243                        case "rotateccw":244                        case "pinch":245                        case "rotate":246                        case "shake":247                        case "tilt":248                            break249                        }250                    }251                }252                return false253            }254        }255    });256    function d(k) {257        k.startMove = (k.startMove) ? k.startMove: {258            startX: null,259            startY: null,260            timestamp: null261        };262        var l = new Date().getTime();263        var m;264        var n;265        if (k.touches) {266            n = [{267                lastX: k.deltaX,268                lastY: k.deltaY,269                moved: null,270                startX: k.screenX - k.startMove.screenX,271                startY: k.screenY - k.startMove.screenY272            }];273            m = {274                vector: k.vector || null,275                orientation: window.orientation || null,276                lastX: ((n[0].lastX > 0) ? +1 : ((n[0].lastX < 0) ? -1 : 0)),277                lastY: ((n[0].lastY > 0) ? +1 : ((n[0].lastY < 0) ? -1 : 0)),278                startX: ((n[0].startX > 0) ? +1 : ((n[0].startX < 0) ? -1 : 0)),279                startY: ((n[0].startY > 0) ? +1 : ((n[0].startY < 0) ? -1 : 0))280            };281            n[0].moved = Math.sqrt(Math.pow(Math.abs(n[0].startX), 2) + Math.pow(Math.abs(n[0].startY), 2))282        }283        return {284            type: k.type || null,285            originalEvent: k.event || null,286            delta: n || null,287            direction: m || {288                orientation: window.orientation || null,289                vector: k.vector || null290            },291            duration: (k.duration) ? k.duration: (k.startMove.timestamp) ? l - k.timestamp: null,292            rotation: k.rotation || null,293            scale: k.scale || null,294            description: k.description || [k.type, ":", k.touches, ":", ((n[0].lastX != 0) ? ((n[0].lastX > 0) ? "right": "left") : "steady"), ":", ((n[0].lastY != 0) ? ((n[0].lastY > 0) ? "down": "up") : "steady")].join("")295        }296    }297    function a(l) {298        var k = ["landscape:clockwise:", "portrait:default:", "landscape:counterclockwise:", "portrait:upsidedown:"];299        c(window).triggerHandler("orientationchange", {300            direction: {301                orientation: window.orientation302            },303            description: ["orientationchange:", k[((window.orientation / 90) + 1)], window.orientation].join("")304        })305    }306    function b(r) {307        var k;308        var t = jQuery(window);309        var o = t.data("ojQueryGestures");310        var m = c.jGestures.defaults.thresholdShake;311        var n = o.oDeviceMotionLastDevicePosition || {312            accelerationIncludingGravity: {313                x: 0,314                y: 0,315                z: 0316            },317            shake: {318                eventCount: 0,319                intervalsPassed: 0,320                intervalsFreeze: 0321            },322            shakeleftright: {323                eventCount: 0,324                intervalsPassed: 0,325                intervalsFreeze: 0326            },327            shakefrontback: {328                eventCount: 0,329                intervalsPassed: 0,330                intervalsFreeze: 0331            },332            shakeupdown: {333                eventCount: 0,334                intervalsPassed: 0,335                intervalsFreeze: 0336            }337        };338        var q = {339            accelerationIncludingGravity: {340                x: r.accelerationIncludingGravity.x,341                y: r.accelerationIncludingGravity.y,342                z: r.accelerationIncludingGravity.z343            },344            shake: {345                eventCount: n.shake.eventCount,346                intervalsPassed: n.shake.intervalsPassed,347                intervalsFreeze: n.shake.intervalsFreeze348            },349            shakeleftright: {350                eventCount: n.shakeleftright.eventCount,351                intervalsPassed: n.shakeleftright.intervalsPassed,352                intervalsFreeze: n.shakeleftright.intervalsFreeze353            },354            shakefrontback: {355                eventCount: n.shakefrontback.eventCount,356                intervalsPassed: n.shakefrontback.intervalsPassed,357                intervalsFreeze: n.shakefrontback.intervalsFreeze358            },359            shakeupdown: {360                eventCount: n.shakeupdown.eventCount,361                intervalsPassed: n.shakeupdown.intervalsPassed,362                intervalsFreeze: n.shakeupdown.intervalsFreeze363            }364        };365        var p;366        var s;367        var l;368        for (k in o) {369            switch (k) {370            case "shake":371            case "shakeleftright":372            case "shakefrontback":373            case "shakeupdown":374                p = [];375                s = [];376                p.push(k);377                if (++q[k].intervalsFreeze > m.freezeShakes && q[k].intervalsFreeze < (2 * m.freezeShakes)) {378                    break379                }380                q[k].intervalsFreeze = 0;381                q[k].intervalsPassed++;382                if ((k === "shake" || k === "shakeleftright") && (q.accelerationIncludingGravity.x > m.leftright.sensitivity || q.accelerationIncludingGravity.x < ( - 1 * m.leftright.sensitivity))) {383                    p.push("leftright");384                    p.push("x-axis")385                }386                if ((k === "shake" || k === "shakefrontback") && (q.accelerationIncludingGravity.y > m.frontback.sensitivity || q.accelerationIncludingGravity.y < ( - 1 * m.frontback.sensitivity))) {387                    p.push("frontback");388                    p.push("y-axis")389                }390                if ((k === "shake" || k === "shakeupdown") && (q.accelerationIncludingGravity.z + 9.81 > m.updown.sensitivity || q.accelerationIncludingGravity.z + 9.81 < ( - 1 * m.updown.sensitivity))) {391                    p.push("updown");392                    p.push("z-axis")393                }394                if (p.length > 1) {395                    if (++q[k].eventCount == m.requiredShakes && (q[k].intervalsPassed) < m.freezeShakes) {396                        t.triggerHandler(k, d({397                            type: k,398                            description: p.join(":"),399                            event: r,400                            duration: q[k].intervalsPassed * 5401                        }));402                        q[k].eventCount = 0;403                        q[k].intervalsPassed = 0;404                        q[k].intervalsFreeze = m.freezeShakes + 1405                    } else {406                        if (q[k].eventCount == m.requiredShakes && (q[k].intervalsPassed) > m.freezeShakes) {407                            q[k].eventCount = 0;408                            q[k].intervalsPassed = 0409                        }410                    }411                }412                break413            }414            l = {};415            l.oDeviceMotionLastDevicePosition = q;416            t.data("ojQueryGestures", c.extend(true, o, l))417        }418    }419    function h(l) {420        var k = jQuery(l.currentTarget);421        k.triggerHandler(c.jGestures.events.touchstart, l);422        if (c.hasGestures) {423            l.currentTarget.addEventListener("touchmove", g, false);424            l.currentTarget.addEventListener("touchend", j, false)425        } else {426            k.bind("mousemove", g);427            k.bind("mouseup", j)428        }429        var n = k.data("ojQueryGestures");430        var m = (l.touches) ? l.touches[0] : l;431        var o = {};432        o.oLastSwipemove = {433            screenX: m.screenX,434            screenY: m.screenY,435            timestamp: new Date().getTime()436        };437        o.oStartTouch = {438            screenX: m.screenX,439            screenY: m.screenY,440            timestamp: new Date().getTime()441        };442        k.data("ojQueryGestures", c.extend(true, n, o))443    }444    function g(t) {445        var v = jQuery(t.currentTarget);446        var s = v.data("ojQueryGestures");447        var q = !!t.touches;448        var l = (q) ? t.changedTouches[0].screenX: t.screenX;449        var k = (q) ? t.changedTouches[0].screenY: t.screenY;450        var r = s.oLastSwipemove;451        var o = l - r.screenX;452        var n = k - r.screenY;453        var u;454        if ( !! s.oLastSwipemove) {455            u = d({456                type: "swipemove",457                touches: (q) ? t.touches.length: "1",458                screenY: k,459                screenX: l,460                deltaY: n,461                deltaX: o,462                startMove: r,463                event: t,464                timestamp: r.timestamp465            });466            v.triggerHandler(u.type, u)467        }468        var m = {};469        var p = (t.touches) ? t.touches[0] : t;470        m.oLastSwipemove = {471            screenX: p.screenX,472            screenY: p.screenY,473            timestamp: new Date().getTime()474        };475        v.data("ojQueryGestures", c.extend(true, s, m))476    }477    function j(r) {478        var v = jQuery(r.currentTarget);479        var x = !!r.changedTouches;480        var u = (x) ? r.changedTouches.length: "1";481        var p = (x) ? r.changedTouches[0].screenX: r.screenX;482        var o = (x) ? r.changedTouches[0].screenY: r.screenY;483        v.triggerHandler(c.jGestures.events.touchendStart, r);484        if (c.hasGestures) {485            r.currentTarget.removeEventListener("touchmove", g, false);486            r.currentTarget.removeEventListener("touchend", j, false)487        } else {488            v.unbind("mousemove", g);489            v.unbind("mouseup", j)490        }491        var m = v.data("ojQueryGestures");492        var y = (Math.abs(m.oStartTouch.screenX - p) > c.jGestures.defaults.thresholdMove || Math.abs(m.oStartTouch.screenY - o) > c.jGestures.defaults.thresholdMove) ? true: false;493        var B = (Math.abs(m.oStartTouch.screenX - p) > c.jGestures.defaults.thresholdSwipe || Math.abs(m.oStartTouch.screenY - o) > c.jGestures.defaults.thresholdSwipe) ? true: false;494        var A;495        var t;496        var n;497        var l;498        var k;499        var q;500        var w = ["zero", "one", "two", "three", "four"];501        var s;502        for (A in m) {503            t = m.oStartTouch;504            n = {};505            p = (x) ? r.changedTouches[0].screenX: r.screenX;506            o = (x) ? r.changedTouches[0].screenY: r.screenY;507            l = p - t.screenX;508            k = o - t.screenY;509            q = d({510                type: "swipe",511                touches: u,512                screenY: o,513                screenX: p,514                deltaY: k,515                deltaX: l,516                startMove: t,517                event: r,518                timestamp: t.timestamp519            });520            s = false;521            switch (A) {522            case "swipeone":523                if (x === false && u == 1 && y === false) {524                    break525                }526                if (x === false || (u == 1 && y === true && B === true)) {527                    s = true;528                    q.type = ["swipe", w[u]].join("");529                    v.triggerHandler(q.type, q)530                }531                break;532            case "swipetwo":533                if ((x && u == 2 && y === true && B === true)) {534                    s = true;535                    q.type = ["swipe", w[u]].join("");536                    v.triggerHandler(q.type, q)537                }538                break;539            case "swipethree":540                if ((x && u == 3 && y === true && B === true)) {541                    s = true;542                    q.type = ["swipe", w[u]].join("");543                    v.triggerHandler(q.type, q)544                }545                break;546            case "swipefour":547                if ((x && u == 4 && y === true && B === true)) {548                    s = true;549                    q.type = ["swipe", w[u]].join("");550                    v.triggerHandler(q.type, q)551                }552                break;553            case "swipeup":554            case "swiperightup":555            case "swiperight":556            case "swiperightdown":557            case "swipedown":558            case "swipeleftdown":559            case "swipeleft":560            case "swipeleftup":561                if (x && y === true && B === true) {562                    s = true;563                    q.type = ["swipe", ((q.delta[0].lastX != 0) ? ((q.delta[0].lastX > 0) ? "right": "left") : ""), ((q.delta[0].lastY != 0) ? ((q.delta[0].lastY > 0) ? "down": "up") : "")].join("");564                    v.triggerHandler(q.type, q)565                }566                break;567            case "tapone":568            case "taptwo":569            case "tapthree":570            case "tapfour":571                if ((y !== true && s !== true) && (w[u] == A.slice(3))) {572                    q.description = ["tap", w[u]].join("");573                    q.type = ["tap", w[u]].join("");574                    v.triggerHandler(q.type, q)575                }576                break577            }578            var z = {};579            v.data("ojQueryGestures", c.extend(true, m, z));580            v.data("ojQueryGestures", c.extend(true, m, z))581        }582        v.triggerHandler(c.jGestures.events.touchendProcessed, r)583    }584    function e(l) {585        var k = jQuery(l.currentTarget);586        k.triggerHandler(c.jGestures.events.gesturestart, l);587        var m = k.data("ojQueryGestures");588        var n = {};589        n.oStartTouch = {590            timestamp: new Date().getTime()591        };592        k.data("ojQueryGestures", c.extend(true, m, n))593    }594    function f(l) {595        var k = jQuery(l.currentTarget);596        var p, m, r, o;597        var q = k.data("ojQueryGestures");598        var n;599        for (n in q) {600            switch (n) {601            case "pinch":602                p = l.scale;603                if (((p < 1) && (p % 1) < (1 - c.jGestures.defaults.thresholdPinchclose)) || ((p > 1) && (p % 1) > (c.jGestures.defaults.thresholdPinchopen))) {604                    m = (p < 1) ? -1 : +1;605                    o = d({606                        type: "pinch",607                        scale: p,608                        touches: null,609                        startMove: q.oStartTouch,610                        event: l,611                        timestamp: q.oStartTouch.timestamp,612                        vector: m,613                        description: ["pinch:", m, ":", ((p < 1) ? "close": "open")].join("")614                    });615                    k.triggerHandler(o.type, o)616                }617                break;618            case "rotate":619                p = l.rotation;620                if (((p < 1) && ( - 1 * (p) > c.jGestures.defaults.thresholdRotateccw)) || ((p > 1) && (p > c.jGestures.defaults.thresholdRotatecw))) {621                    m = (p < 1) ? -1 : +1;622                    o = d({623                        type: "rotate",624                        rotation: p,625                        touches: null,626                        startMove: q.oStartTouch,627                        event: l,628                        timestamp: q.oStartTouch.timestamp,629                        vector: m,630                        description: ["rotate:", m, ":", ((p < 1) ? "counterclockwise": "clockwise")].join("")631                    });632                    k.triggerHandler(o.type, o)633                }634                break635            }636        }637    }638    function i(l) {639        var k = jQuery(l.currentTarget);640        k.triggerHandler(c.jGestures.events.gestureendStart, l);641        var n;642        var o = k.data("ojQueryGestures");643        var m;644        for (m in o) {645            switch (m) {646            case "pinchclose":647                n = l.scale;648                if ((n < 1) && (n % 1) < (1 - c.jGestures.defaults.thresholdPinchclose)) {649                    k.triggerHandler("pinchclose", d({650                        type: "pinchclose",651                        scale: n,652                        vector: -1,653                        touches: null,654                        startMove: o.oStartTouch,655                        event: l,656                        timestamp: o.oStartTouch.timestamp,657                        description: "pinch:-1:close"658                    }))659                }660                break;661            case "pinchopen":662                n = l.scale;663                if ((n > 1) && (n % 1) > (c.jGestures.defaults.thresholdPinchopen)) {664                    k.triggerHandler("pinchopen", d({665                        type: "pinchopen",666                        scale: n,667                        vector: +1,668                        touches: null,669                        startMove: o.oStartTouch,670                        event: l,671                        timestamp: o.oStartTouch.timestamp,672                        description: "pinch:+1:open"673                    }))674                }675                break;676            case "rotatecw":677                n = l.rotation;678                if ((n > 1) && (n > c.jGestures.defaults.thresholdRotatecw)) {679                    k.triggerHandler("rotatecw", d({680                        type: "rotatecw",681                        rotation: n,682                        vector: +1,683                        touches: null,684                        startMove: o.oStartTouch,685                        event: l,686                        timestamp: o.oStartTouch.timestamp,687                        description: "rotate:+1:clockwise"688                    }))689                }690                break;691            case "rotateccw":692                n = l.rotation;693                if ((n < 1) && ( - 1 * (n) > c.jGestures.defaults.thresholdRotateccw)) {694                    k.triggerHandler("rotateccw", d({695                        type: "rotateccw",696                        rotation: n,697                        vector: -1,698                        touches: null,699                        startMove: o.oStartTouch,700                        event: l,701                        timestamp: o.oStartTouch.timestamp,702                        description: "rotate:-1:counterclockwise"703                    }))704                }705                break706            }707        }708        k.triggerHandler(c.jGestures.events.gestureendProcessed, l)709    }...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
