PageSourceSearch

https://arco.com/scripts/jquery.touchSwipe.js?v=RcgO7Qr29F

js arco.com collected 2026-10-02 08:46:41 UTC 69,356 bytes, 1,961 lines download raw bytes

1/*
2* @fileOverview TouchSwipe - jQuery Plugin
3* @version 1.6.3
4*
5* @author Matt Bryson http://www.github.com/mattbryson
6* @see https://github.com/mattbryson/TouchSwipe-Jquery-Plugin
7* @see http://labs.skinkers.com/touchSwipe/
8* @see http://plugins.jquery.com/project/touchSwipe
9*
10* Copyright (c) 2010 Matt Bryson
11* Dual licensed under the MIT or GPL Version 2 licenses.
12*
13*
14* Changelog
15* $Date: 2010-12-12 (Wed, 12 Dec 2010) $
16* $version: 1.0.0
17* $version: 1.0.1 - removed multibyte comments
18*
19* $Date: 2011-21-02 (Mon, 21 Feb 2011) $
20* $version: 1.1.0 	- added allowPageScroll property to allow swiping and scrolling of page
21*					- changed handler signatures so one handler can be used for multiple events
22* $Date: 2011-23-02 (Wed, 23 Feb 2011) $
23* $version: 1.2.0 	- added click handler. This is fired if the user simply clicks and does not swipe. The event object and click target are passed to handler.
24*					- If you use the http://code.google.com/p/jquery-ui-for-ipad-and-iphone/ plugin, you can also assign jQuery mouse events to children of a touchSwipe object.
25* $version: 1.2.1 	- removed console log!
26*
27* $version: 1.2.2 	- Fixed bug where scope was not preserved in callback methods.
28*
29* $Date: 2011-28-04 (Thurs, 28 April 2011) $
30* $version: 1.2.4 	- Changed licence terms to be MIT or GPL inline with jQuery. Added check for support of touch events to stop non compatible browsers erroring.
31*
32* $Date: 2011-27-09 (Tues, 27 September 2011) $
33* $version: 1.2.5 	- Added support for testing swipes with mouse on desktop browser (thanks to https://github.com/joelhy)
34*
35* $Date: 2012-14-05 (Mon, 14 May 2012) $
36* $version: 1.2.6 	- Added timeThreshold between start and end touch, so user can ignore slow swipes (thanks to Mark Chase). Default is null, all swipes are detected
37*
38* $Date: 2012-05-06 (Tues, 05 June 2012) $
39* $version: 1.2.7 	- Changed time threshold to have null default for backwards compatibility. Added duration param passed back in events, and refactored how time is handled.
40*
41* $Date: 2012-05-06 (Tues, 05 June 2012) $
42* $version: 1.2.8 	- Added the possibility to return a value like null or false in the trigger callback. In that way we can control when the touch start/move should take effect or not (simply by returning in some cases return null; or return false;) This effects the ontouchstart/ontouchmove event.
43*
44* $Date: 2012-06-06 (Wed, 06 June 2012) $
45* $version: 1.3.0 	- Refactored whole plugin to allow for methods to be executed, as well as exposed defaults for user override. Added 'enable', 'disable', and 'destroy' methods
46*
47* $Date: 2012-05-06 (Fri, 05 June 2012) $
48* $version: 1.3.1 	- Bug fixes  - bind() with false as last argument is no longer supported in jQuery 1.6, also, if you just click, the duration is now returned correctly.
49*
50* $Date: 2012-29-07 (Sun, 29 July 2012) $
51* $version: 1.3.2	- Added fallbackToMouseEvents option to NOT capture mouse events on non touch devices.
52* 			- Added "all" fingers value to the fingers property, so any combinatin of fingers triggers the swipe, allowing event handlers to check the finger count
53*
54* $Date: 2012-09-08 (Thurs, 9 Aug 2012) $
55* $version: 1.3.3	- Code tidy prep for minified version
56*
57* $Date: 2012-04-10 (wed, 4 Oct 2012) $
58* $version: 1.4.0	- Added pinch support, pinchIn and pinchOut
59*
60* $Date: 2012-11-10 (Thurs, 11 Oct 2012) $
61* $version: 1.5.0	- Added excludedElements, a jquery selector that specifies child elements that do NOT trigger swipes. By default, this is one select that removes all form, input select, button and anchor elements.
62*
63* $Date: 2012-22-10 (Mon, 22 Oct 2012) $
64* $version: 1.5.1	- Fixed bug with jQuery 1.8 and trailing comma in excludedElements
65*					- Fixed bug with IE and eventPreventDefault()
66* $Date: 2013-01-12 (Fri, 12 Jan 2013) $
67* $version: 1.6.0	- Fixed bugs with pinching, mainly when both pinch and swipe enabled, as well as adding time threshold for multifinger gestures, so releasing one finger beofre the other doesnt trigger as single finger gesture.
68*					- made the demo site all static local HTML pages so they can be run locally by a developer
69*					- added jsDoc comments and added documentation for the plugin	
70*					- code tidy
71*					- added triggerOnTouchLeave property that will end the event when the user swipes off the element.
72* $Date: 2013-03-23 (Sat, 23 Mar 2013) $
73* $version: 1.6.1	- Added support for ie8 touch events
74* $version: 1.6.2	- Added support for events binding with on / off / bind in jQ for all callback names.
75*                   - Deprecated the 'click' handler in favour of tap.
76*                   - added cancelThreshold property
77*                   - added option method to update init options at runtime
78*
79* $version 1.6.3    - added doubletap, longtap events and longTapThreshold, doubleTapThreshold property
80* $Date: 2013-04-04 (Thurs, 04 April 2013) $
81* $version 1.6.4    - Fixed bug with cancelThreshold introduced in 1.6.3, where swipe status no longer fired start event, and stopped once swiping back.
82*/
83
84/**
85 * See (http://jquery.com/).
86 * @name $
87 * @class 
88 * See the jQuery Library  (http://jquery.com/) for full details.  This just
89 * documents the function and classes that are added to jQuery by this plug-in.
90 */
91 
92/**
93 * See (http://jquery.com/)
94 * @name fn
95 * @class 
96 * See the jQuery Library  (http://jquery.com/) for full details.  This just
97 * documents the function and classes that are added to jQuery by this plug-in.
98 * @memberOf $
99 */
100 
101 
102 
103(function ($) {
104	"use strict";
105
106	//Constants
107	var LEFT = "left",
108		RIGHT = "right",
109		UP = "up",
110		DOWN = "down",
111		IN = "in",
112		OUT = "out",
113
114		NONE = "none",
115		AUTO = "auto",
116		
117		SWIPE = "swipe",
118		PINCH = "pinch",
119		TAP = "tap",
120		DOUBLE_TAP = "doubletap",
121		LONG_TAP = "longtap",
122		
123		HORIZONTAL = "horizontal",
124		VERTICAL = "vertical",
125
126		ALL_FINGERS = "all",
127		
128		DOUBLE_TAP_THRESHOLD = 10,
129
130		PHASE_START = "start",
131		PHASE_MOVE = "move",
132		PHASE_END = "end",
133		PHASE_CANCEL = "cancel",
134
135		SUPPORTS_TOUCH = 'ontouchstart' in window,
136
137		PLUGIN_NS = 'TouchSwipe';
138
139
140
141	/**
142	* The default configuration, and available options to configure touch swipe with.
143	* You can set the default values by updating any of the properties prior to instantiation.
144	* @name $.fn.swipe.defaults
145	* @namespace
146	* @property {int} [fingers=1] The number of fingers to detect in a swipe. Any swipes that do not meet this requirement will NOT trigger swipe handlers.
147	* @property {int} [threshold=75] The number of pixels that the user must move their finger by before it is considered a swipe. 
148	* @property {int} [cancelThreshold=null] The number of pixels that the user must move their finger back from the original swipe direction to cancel the gesture.
149	* @property {int} [pinchThreshold=20] The number of pixels that the user must pinch their finger by before it is considered a pinch. 
150	* @property {int} [maxTimeThreshold=null] Time, in milliseconds, between touchStart and touchEnd must NOT exceed in order to be considered a swipe. 
151	* @property {int} [fingerReleaseThreshold=250] Time in milliseconds between releasing multiple fingers.  If 2 fingers are down, and are released one after the other, if they are within this threshold, it counts as a simultaneous release. 
152	* @property {int} [longTapThreshold=500] Time in milliseconds between tap and release for a long tap
153    * @property {int} [doubleTapThreshold=200] Time in milliseconds between 2 taps to count as a doubletap
154	* @property {function} [swipe=null] A handler to catch all swipes. See {@link $.fn.swipe#event:swipe}
155	* @property {function} [swipeLeft=null] A handler that is triggered for "left" swipes. See {@link $.fn.swipe#event:swipeLeft}
156	* @property {function} [swipeRight=null] A handler that is triggered for "right" swipes. See {@link $.fn.swipe#event:swipeRight}
157	* @property {function} [swipeUp=null] A handler that is triggered for "up" swipes. See {@link $.fn.swipe#event:swipeUp}
158	* @property {function} [swipeDown=null] A handler that is triggered for "down" swipes. See {@link $.fn.swipe#event:swipeDown}
159	* @property {function} [swipeStatus=null] A handler triggered for every phase of the swipe. See {@link $.fn.swipe#event:swipeStatus}
160	* @property {function} [pinchIn=null] A handler triggered for pinch in events. See {@link $.fn.swipe#event:pinchIn}
161	* @property {function} [pinchOut=null] A handler triggered for pinch out events. See {@link $.fn.swipe#event:pinchOut}
162	* @property {function} [pinchStatus=null] A handler triggered for every phase of a pinch. See {@link $.fn.swipe#event:pinchStatus}
163	* @property {function} [tap=null] A handler triggered when a user just taps on the item, rather than swipes it. If they do not move, tap is triggered, if they do move, it is not. 
164	* @property {function} [doubleTap=null] A handler triggered when a user double taps on the item. The delay between taps can be set with the doubleTapThreshold property. See {@link $.fn.swipe.defaults#doubleTapThreshold}
165	* @property {function} [longTap=null] A handler triggered when a user long taps on the item. The delay between start and end can be set with the longTapThreshold property. See {@link $.fn.swipe.defaults#doubleTapThreshold}
166	* @property {boolean} [triggerOnTouchEnd=true] If true, the swipe events are triggered when the touch end event is received (user releases finger).  If false, it will be triggered on reaching the threshold, and then cancel the touch event automatically. 
167	* @property {boolean} [triggerOnTouchLeave=false] If true, then when the user leaves the swipe object, the swipe will end and trigger appropriate handlers. 
168	* @property {string} [allowPageScroll='auto'] How the browser handles page scrolls when the user is swiping on a touchSwipe object. See {@link $.fn.swipe.pageScroll}.  <br/><br/>
169										<code>"auto"</code> : all undefined swipes will cause the page to scroll in that direction. <br/>
170										<code>"none"</code> : the page will not scroll when user swipes. <br/>
171										<code>"horizontal"</code> : will force page to scroll on horizontal swipes. <br/>
172										<code>"vertical"</code> : will force page to scroll on vertical swipes. <br/>
173	* @property {boolean} [fallbackToMouseEvents=true] If true mouse events are used when run on a non touch device, false will stop swipes being triggered by mouse events on non tocuh devices. 
174	* @property {string} [excludedElements="button, input, select, textarea, a, .noSwipe"] A jquery selector that specifies child elements that do NOT trigger swipes. By default this excludes all form, input, select, button, anchor and .noSwipe elements. 
175	
176	*/
177	var defaults = {
178		fingers: 1, 		
179		threshold: 75, 	
180		cancelThreshold:null,	
181		pinchThreshold:20,
182		maxTimeThreshold: null, 
183		fingerReleaseThreshold:250, 
184		longTapThreshold:500,
185		doubleTapThreshold:200,
186		swipe: null, 		
187		swipeLeft: null, 	
188		swipeRight: null, 	
189		swipeUp: null, 		
190		swipeDown: null, 	
191		swipeStatus: null, 	
192		pinchIn:null,		
193		pinchOut:null,		
194		pinchStatus:null,	
195		click:null, //Deprecated since 1.6.2
196		tap:null,
197		doubleTap:null,
198		longTap:null, 		
199		triggerOnTouchEnd: true, 
200		triggerOnTouchLeave:false, 
201		allowPageScroll: "auto", 
202		fallbackToMouseEvents: true,	
203		excludedElements:"button, input, select, textarea, a, .noSwipe"
204	};
205
206
207
208	/**
209	* Applies TouchSwipe behaviour to one or more jQuery objects.
210	* The TouchSwipe plugin can be instantiated via this method, or methods within 
211	* TouchSwipe can be executed via this method as per jQuery plugin architecture.
212	* @see TouchSwipe
213	* @class
214	* @param {Mixed} method If the current DOMNode is a TouchSwipe object, and <code>method</code> is a TouchSwipe method, then
215	* the <code>method</code> is executed, and any following arguments are passed to the TouchSwipe method.
216	* If <code>method</code> is an object, then the TouchSwipe class is instantiated on the current DOMNode, passing the 
217	* configuration properties defined in the object. See TouchSwipe
218	*
219	*/
220	$.fn.swipe = function (method) {
221		var $this = $(this),
222			plugin = $this.data(PLUGIN_NS);
223
224		//Check if we are already instantiated and trying to execute a method	
225		if (plugin && typeof method === 'string') {
226			if (plugin[method]) {
227				return plugin[method].apply(this, Array.prototype.slice.call(arguments, 1));
228			} else {
229				$.error('Method ' + method + ' does not exist on jQuery.swipe');
230			}
231		}
232		//Else not instantiated and trying to pass init object (or nothing)
233		else if (!plugin && (typeof method === 'object' || !method)) {
234			return init.apply(this, arguments);
235		}
236
237		return $this;
238	};
239
240	//Expose our defaults so a user could override the plugin defaults
241	$.fn.swipe.defaults = defaults;
242
243	/**
244	* The phases that a touch event goes through.  The <code>phase</code> is passed to the event handlers. 
245	* These properties are read only, attempting to change them will not alter the values passed to the event handlers.
246	* @namespace
247	* @readonly
248	* @property {string} PHASE_START Constant indicating the start phase of the touch event. Value is <code>"start"</code>.
249	* @property {string} PHASE_MOVE Constant indicating the move phase of the touch event. Value is <code>"move"</code>.
250	* @property {string} PHASE_END Constant indicating the end phase of the touch event. Value is <code>"end"</code>.
251	* @property {string} PHASE_CANCEL Constant indicating the cancel phase of the touch event. Value is <code>"cancel"</code>.
252	*/
253	$.fn.swipe.phases = {
254		PHASE_START: PHASE_START,
255		PHASE_MOVE: PHASE_MOVE,
256		PHASE_END: PHASE_END,
257		PHASE_CANCEL: PHASE_CANCEL
258	};
259
260	/**
261	* The direction constants that are passed to the event handlers. 
262	* These properties are read only, attempting to change them will not alter the values passed to the event handlers.
263	* @namespace
264	* @readonly
265	* @property {string} LEFT Constant indicating the left direction. Value is <code>"left"</code>.
266	* @property {string} RIGHT Constant indicating the right direction. Value is <code>"right"</code>.
267	* @property {string} UP Constant indicating the up direction. Value is <code>"up"</code>.
268	* @property {string} DOWN Constant indicating the down direction. Value is <code>"cancel"</code>.
269	* @property {string} IN Constant indicating the in direction. Value is <code>"in"</code>.
270	* @property {string} OUT Constant indicating the out direction. Value is <code>"out"</code>.
271	*/
272	$.fn.swipe.directions = {
273		LEFT: LEFT,
274		RIGHT: RIGHT,
275		UP: UP,
276		DOWN: DOWN,
277		IN : IN,
278		OUT: OUT
279	};
280	
281	/**
282	* The page scroll constants that can be used to set the value of <code>allowPageScroll</code> option
283	* These properties are read only
284	* @namespace
285	* @readonly
286	* @see $.fn.swipe.defaults#allowPageScroll
287	* @property {string} NONE Constant indicating no page scrolling is allowed. Value is <code>"none"</code>.
288	* @property {string} HORIZONTAL Constant indicating horizontal page scrolling is allowed. Value is <code>"horizontal"</code>.
289	* @property {string} VERTICAL Constant indicating vertical page scrolling is allowed. Value is <code>"vertical"</code>.
290	* @property {string} AUTO Constant indicating either horizontal or vertical will be allowed, depending on the swipe handlers registered. Value is <code>"auto"</code>.
291	*/
292	$.fn.swipe.pageScroll = {
293		NONE: NONE,
294		HORIZONTAL: HORIZONTAL,
295		VERTICAL: VERTICAL,
296		AUTO: AUTO
297	};
298
299	/**
300	* Constants representing the number of fingers used in a swipe.  These are used to set both the value of <code>fingers</code> in the 
301	* options object, as well as the value of the <code>fingers</code> event property.
302	* These properties are read only, attempting to change them will not alter the values passed to the event handlers.
303	* @namespace
304	* @readonly
305	* @see $.fn.swipe.defaults#fingers
306	* @property {string} ONE Constant indicating 1 finger is to be detected / was detected. Value is <code>1</code>.
307	* @property {string} TWO Constant indicating 2 fingers are to be detected / were detected. Value is <code>1</code>.
308	* @property {string} THREE Constant indicating 3 finger are to be detected / were detected. Value is <code>1</code>.
309	* @property {string} ALL Constant indicating any combination of finger are to be detected.  Value is <code>"all"</code>.
310	*/
311	$.fn.swipe.fingers = {
312		ONE: 1,
313		TWO: 2,
314		THREE: 3,
315		ALL: ALL_FINGERS
316	};
317
318	/**
319	* Initialise the plugin for each DOM element matched
320	* This creates a new instance of the main TouchSwipe class for each DOM element, and then
321	* saves a reference to that instance in the elements data property.
322	* @internal
323	*/
324	function init(options) {
325		//Prep and extend the options
326		if (options && (options.allowPageScroll === undefined && (options.swipe !== undefined || options.swipeStatus !== undefined))) {
327			options.allowPageScroll = NONE;
328		}
329		
330        //Check for deprecated options
331		//Ensure that any old click handlers are assigned to the new tap, unless we have a tap
332		if(options.click!==undefined && options.tap===undefined) {
333		    options.tap = options.click;
334		}
335
336		if (!options) {
337			options = {};
338		}
339		
340        //pass empty object so we dont modify the defaults
341		options = $.extend({}, $.fn.swipe.defaults, options);
342
343		//For each element instantiate the plugin
344		return this.each(function () {
345			var $this = $(this);
346
347			//Check we havent already initialised the plugin
348			var plugin = $this.data(PLUGIN_NS);
349
350			if (!plugin) {
351				plugin = new TouchSwipe(this, options);
352				$this.data(PLUGIN_NS, plugin);
353			}
354		});
355	}
356
357	/**
358	* Main TouchSwipe Plugin Class.
359	* Do not use this to construct your TouchSwipe object, use the jQuery plugin method $.fn.swipe(); {@link $.fn.swipe}
360	* @private
361	* @name TouchSwipe
362	* @param {DOMNode} element The HTML DOM object to apply to plugin to
363	* @param {Object} options The options to configure the plugin with.  @link {$.fn.swipe.defaults}
364	* @see $.fh.swipe.defaults
365	* @see $.fh.swipe
366    * @class
367	*/
368	function TouchSwipe(element, options) {
369		var useTouchEvents = (SUPPORTS_TOUCH || !options.fallbackToMouseEvents),
370			START_EV = useTouchEvents ? 'touchstart' : 'mousedown',
371			MOVE_EV = useTouchEvents ? 'touchmove' : 'mousemove',
372			END_EV = useTouchEvents ? 'touchend' : 'mouseup',
373			LEAVE_EV = useTouchEvents ? null : 'mouseleave', //we manually detect leave on touch devices, so null event here
374			CANCEL_EV = 'touchcancel';
375
376
377
378		//touch properties
379		var distance = 0,
380			direction = null,
381			duration = 0,
382			startTouchesDistance = 0,
383			endTouchesDistance = 0,
384			pinchZoom = 1,
385			pinchDistance = 0,
386			pinchDirection = 0,
387			maximumsMap=null;
388
389		
390		
391		//jQuery wrapped element for this instance
392		var $element = $(element);
393		
394		//Current phase of th touch cycle
395		var phase = "start";
396
397		// the current number of fingers being used.
398		var fingerCount = 0; 			
399
400		//track mouse points / delta
401		var fingerData=null;
402
403		//track times
404		var startTime = 0,
405			endTime = 0,
406			previousTouchEndTime=0,
407			previousTouchFingerCount=0,
408			doubleTapStartTime=0;
409
410        //Timeouts
411        var singleTapTimeout=null;
412        
413		// Add gestures to all swipable areas if supported
414		try {
415			$element.bind(START_EV, touchStart);
416			$element.bind(CANCEL_EV, touchCancel);
417		}
418		catch (e) {
419			$.error('events not supported ' + START_EV + ',' + CANCEL_EV + ' on jQuery.swipe');
420		}
421
422		//
423		//Public methods
424		//
425		
426		/**
427		* re-enables the swipe plugin with the previous configuration
428		* @function
429		* @name $.fn.swipe#enable
430		* @return {DOMNode} The Dom element that was registered with TouchSwipe 
431		* @example $("#element").swipe("enable");
432		*/
433		this.enable = function () {
434			$element.bind(START_EV, touchStart);
435			$element.bind(CANCEL_EV, touchCancel);
436			return $element;
437		};
438
439		/**
440		* disables the swipe plugin
441		* @function
442		* @name $.fn.swipe#disable
443		* @return {DOMNode} The Dom element that is now registered with TouchSwipe
444	    * @example $("#element").swipe("disable");
445		*/
446		this.disable = function () {
447			removeListeners();
448			return $element;
449		};
450
451		/**
452		* Destroy the swipe plugin completely. To use any swipe methods, you must re initialise the plugin.
453		* @function
454		* @name $.fn.swipe#destroy
455		* @return {DOMNode} The Dom element that was registered with TouchSwipe 
456		* @example $("#element").swipe("destroy");
457		*/
458		this.destroy = function () {
459			removeListeners();
460			$element.data(PLUGIN_NS, null);
461			return $element;
462		};
463
464
465        /**
466         * Allows run time updating of the swipe configuration options.
467         * @function
468    	 * @name $.fn.swipe#option
469    	 * @param {String} property The option property to get or set
470         * @param {Object} [value] The value to set the property to
471		 * @return {Object} If only a property name is passed, then that property value is returned.
472		 * @example $("#element").swipe("option", "threshold"); // return the threshold
473         * @example $("#element").swipe("option", "threshold", 100); // set the threshold after init
474         * @see $.fn.swipe.defaults
475         *
476         */
477        this.option = function (property, value) {
478            if(options[property]!==undefined) {
479                if(value===undefined) {
480                    return options[property];
481                } else {
482                    options[property] = value;
483                }
484            } else {
485                $.error('Option ' + property + ' does not exist on jQuery.swipe.options');
486            }
487        }
488
489		//
490		// Private methods
491		//
492		
493		//
494		// EVENTS
495		//
496		/**
497		* Event handler for a touch start event.
498		* Stops the default click event from triggering and stores where we touched
499		* @inner
500		* @param {object} jqEvent The normalised jQuery event object.
501		*/
502		function touchStart(jqEvent) {
503			//If we already in a touch event (a finger already in use) then ignore subsequent ones..
504			if( getTouchInProgress() )
505				return;
506			
507			//Check if this element matches any in the excluded elements selectors,  or its parent is excluded, if so, DONT swipe
508			if( $(jqEvent.target).closest( options.excludedElements, $element ).length>0 ) 
509				return;
510				
511			//As we use Jquery bind for events, we need to target the original event object
512			//If these events are being programatically triggered, we dont have an orignal event object, so use the Jq one.
513			var event = jqEvent.originalEvent ? jqEvent.originalEvent : jqEvent;
514			
515			var ret,
516				evt = SUPPORTS_TOUCH ? event.touches[0] : event;
517
518			phase = PHASE_START;
519
520			//If we support touches, get the finger count
521			if (SUPPORTS_TOUCH) {
522				// get the total number of fingers touching the screen
523				fingerCount = event.touches.length;
524			}
525			//Else this is the desktop, so stop the browser from dragging the image
526			else {
527				jqEvent.preventDefault(); //call this on jq event so we are cross browser
528			}
529
530			//clear vars..
531			distance = 0;
532			direction = null;
533			pinchDirection=null;
534			duration = 0;
535			startTouchesDistance=0;
536			endTouchesDistance=0;
537			pinchZoom = 1;
538			pinchDistance = 0;
539			fingerData=createAllFingerData();
540			maximumsMap=createMaximumsData();
541			cancelMultiFingerRelease();
542
543			
544			// check the number of fingers is what we are looking for, or we are capturing pinches
545			if (!SUPPORTS_TOUCH || (fingerCount === options.fingers || options.fingers === ALL_FINGERS) || hasPinches()) {
546				// get the coordinates of the touch
547				createFingerData( 0, evt );
548				startTime = getTimeStamp();
549				
550				if(fingerCount==2) {
551					//Keep track of the initial pinch distance, so we can calculate the diff later
552					//Store second finger data as start
553					createFingerData( 1, event.touches[1] );
554					startTouchesDistance = endTouchesDistance = calculateTouchesDistance(fingerData[0].start, fingerData[1].start);
555				}
556				
557				if (options.swipeStatus || options.pinchStatus) {
558					ret = triggerHandler(event, phase);
559				}
560			}
561			else {
562				//A touch with more or less than the fingers we are looking for, so cancel
563				ret = false; 
564			}
565
566			//If we have a return value from the users handler, then return and cancel
567			if (ret === false) {
568				phase = PHASE_CANCEL;
569				triggerHandler(event, phase);
570				return ret;
571			}
572			else {
573				setTouchInProgress(true);
574			}
575		};
576		
577		
578		
579		/**
580		* Event handler for a touch move event. 
581		* If we change fingers during move, then cancel the event
582		* @inner
583		* @param {object} jqEvent The normalised jQuery event object.
584		*/
585		function touchMove(jqEvent) {
586			
587			//As we use Jquery bind for events, we need to target the original event object
588			//If these events are being programatically triggered, we dont have an orignal event object, so use the Jq one.
589			var event = jqEvent.originalEvent ? jqEvent.originalEvent : jqEvent;
590			
591			//If we are ending, cancelling, or within the threshold of 2 fingers being released, dont track anything..
592			if (phase === PHASE_END || phase === PHASE_CANCEL || inMultiFingerRelease())
593				return;
594
595			var ret,
596				evt = SUPPORTS_TOUCH ? event.touches[0] : event;
597			
598
599			//Update the  finger data 
600			var currentFinger = updateFingerData(evt);
601			endTime = getTimeStamp();
602			
603			if (SUPPORTS_TOUCH) {
604				fingerCount = event.touches.length;
605			}
606
607			phase = PHASE_MOVE;
608
609			//If we have 2 fingers get Touches distance as well
610			if(fingerCount==2) {
611				
612				//Keep track of the initial pinch distance, so we can calculate the diff later
613				//We do this here as well as the start event, incase they start with 1 finger, and the press 2 fingers
614				if(startTouchesDistance==0) {
615					//Create second finger if this is the first time...
616					createFingerData( 1, event.touches[1] );
617					
618					startTouchesDistance = endTouchesDistance = calculateTouchesDistance(fingerData[0].start, fingerData[1].start);
619				} else {
620					//Else just update the second finger
621					updateFingerData(event.touches[1]);
622				
623					endTouchesDistance = calculateTouchesDistance(fingerData[0].end, fingerData[1].end);
624					pinchDirection = calculatePinchDirection(fingerData[0].end, fingerData[1].end);
625				}
626				
627				
628				pinchZoom = calculatePinchZoom(startTouchesDistance, endTouchesDistance);
629				pinchDistance = Math.abs(startTouchesDistance - endTouchesDistance);
630			}
631			
632			
633			if ( (fingerCount === options.fingers || options.fingers === ALL_FINGERS) || !SUPPORTS_TOUCH || hasPinches() ) {
634				
635				direction = calculateDirection(currentFinger.start, currentFinger.end);
636				
637				//Check if we need to prevent default evnet (page scroll / pinch zoom) or not
638				validateDefaultEvent(jqEvent, direction);
639
640				//Distance and duration are all off the main finger
641				distance = calculateDistance(currentFinger.start, currentFinger.end);
642				duration = calculateDuration();
643
644                //Cache the maximum distance we made in this direction
645                setMaxDistance(direction, distance);
646
647
648				if (options.swipeStatus || options.pinchStatus) {
649					ret = triggerHandler(event, phase);
650				}
651				
652				
653				//If we trigger end events when threshold are met, or trigger events when touch leves element
654				if(!options.triggerOnTouchEnd || options.triggerOnTouchLeave) {
655					
656					var inBounds = true;
657					
658					//If checking if we leave the element, run the bounds check (we can use touchleave as its not supported on webkit)
659					if(options.triggerOnTouchLeave) {
660						var bounds = getbounds( this );
661						inBounds = isInBounds( currentFinger.end, bounds );
662					}
663					
664					//Trigger end handles as we swipe if thresholds met or if we have left the element if the user has asked to check these..
665					if(!options.triggerOnTouchEnd && inBounds) {
666						phase = getNextPhase( PHASE_MOVE );
667					} 
668					//We end if out of bounds here, so set current phase to END, and check if its modified 
669					else if(options.triggerOnTouchLeave && !inBounds ) {
670						phase = getNextPhase( PHASE_END );
671					}
672						
673					if(phase==PHASE_CANCEL || phase==PHASE_END)	{
674						triggerHandler(event, phase);
675					}				
676				}
677			}
678			else {
679				phase = PHASE_CANCEL;
680				triggerHandler(event, phase);
681			}
682
683			if (ret === false) {
684				phase = PHASE_CANCEL;
685				triggerHandler(event, phase);
686			}
687		}
688
689
690
691		/**
692		* Event handler for a touch end event. 
693		* Calculate the direction and trigger events
694		* @inner
695		* @param {object} jqEvent The normalised jQuery event object.
696		*/
697		function touchEnd(jqEvent) {
698			//As we use Jquery bind for events, we need to target the original event object
699			var event = jqEvent.originalEvent;
700				
701
702			//If we are still in a touch with another finger return
703			//This allows us to wait a fraction and see if the other finger comes up, if it does within the threshold, then we treat it as a multi release, not a single release.
704			if (SUPPORTS_TOUCH) {
705				if(event.touches.length>0) {
706					startMultiFingerRelease();
707					return true;
708				}
709			}
710			
711			//If a previous finger has been released, check how long ago, if within the threshold, then assume it was a multifinger release.
712			//This is used to allow 2 fingers to release fractionally after each other, whilst maintainig the event as containg 2 fingers, not 1
713			if(inMultiFingerRelease()) {	
714				fingerCount=previousTouchFingerCount;
715			}	
716				 
717			//call this on jq event so we are cross browser 
718			jqEvent.preventDefault(); 
719			
720			//Set end of swipe
721			endTime = getTimeStamp();
722			
723			//Get duration incase move was never fired
724			duration = calculateDuration();
725			
726			//If we trigger handlers at end of swipe OR, we trigger during, but they didnt trigger and we are still in the move phase
727			if(didSwipeBackToCancel()) {
728			    phase = PHASE_CANCEL;
729                triggerHandler(event, phase);
730			} else if (options.triggerOnTouchEnd || (options.triggerOnTouchEnd == false && phase === PHASE_MOVE)) {
731				phase = PHASE_END;
732                triggerHandler(event, phase);
733			}
734			//Special cases - A tap should always fire on touch end regardless,
735			//So here we manually trigger the tap end handler by itself
736			//We dont run trigger handler as it will re-trigger events that may have fired already
737			else if (!options.triggerOnTouchEnd && hasTap()) {
738                //Trigger the pinch events...
739			    phase = PHASE_END;
740			    triggerHandlerForGesture(event, phase, TAP);
741			}
742			else if (phase === PHASE_MOVE) {
743				phase = PHASE_CANCEL;
744				triggerHandler(event, phase);
745			}
746
747			setTouchInProgress(false);
748		}
749
750
751
752		/**
753		* Event handler for a touch cancel event. 
754		* Clears current vars
755		* @inner
756		*/
757		function touchCancel() {
758			// reset the variables back to default values
759			fingerCount = 0;
760			endTime = 0;
761			startTime = 0;
762			startTouchesDistance=0;
763			endTouchesDistance=0;
764			pinchZoom=1;
765			
766			//If we were in progress of tracking a possible multi touch end, then re set it.
767			cancelMultiFingerRelease();
768			
769			setTouchInProgress(false);
770		}
771		
772		
773		/**
774		* Event handler for a touch leave event. 
775		* This is only triggered on desktops, in touch we work this out manually
776		* as the touchleave event is not supported in webkit
777		* @inner
778		*/
779		function touchLeave(jqEvent) {
780			var event = jqEvent.originalEvent;
781			
782			//If we have the trigger on leve property set....
783			if(options.triggerOnTouchLeave) {
784				phase = getNextPhase( PHASE_END );
785				triggerHandler(event, phase);
786			}
787		}
788		
789		/**
790		* Removes all listeners that were associated with the plugin
791		* @inner
792		*/
793		function removeListeners() {
794			$element.unbind(START_EV, touchStart);
795			$element.unbind(CANCEL_EV, touchCancel);
796			$element.unbind(MOVE_EV, touchMove);
797			$element.unbind(END_EV, touchEnd);
798			
799			//we only have leave events on desktop, we manually calcuate leave on touch as its not supported in webkit
800			if(LEAVE_EV) { 
801				$element.unbind(LEAVE_EV, touchLeave);
802			}
803			
804			setTouchInProgress(false);
805		}
806
807		
808		/**
809		 * Checks if the time and distance thresholds have been met, and if so then the appropriate handlers are fired.
810		 */
811		function getNextPhase(currentPhase) {
812			
813			var nextPhase = currentPhase;
814			
815			// Ensure we have valid swipe (under time and over distance  and check if we are out of bound...)
816			var validTime = validateSwipeTime();
817			var validDistance = validateSwipeDistance();
818			var didCancel = didSwipeBackToCancel();
819						
820			//If we have exceeded our time, then cancel	
821			if(!validTime || didCancel) {
822				nextPhase = PHASE_CANCEL;
823			}
824			//Else if we are moving, and have reached distance then end
825			else if (validDistance && currentPhase == PHASE_MOVE && (!options.triggerOnTouchEnd || options.triggerOnTouchLeave) ) {
826				nextPhase = PHASE_END;
827			} 
828			//Else if we have ended by leaving and didnt reach distance, then cancel
829			else if (!validDistance && currentPhase==PHASE_END && options.triggerOnTouchLeave) {
830				nextPhase = PHASE_CANCEL;
831			}
832			
833			return nextPhase;
834		}
835		
836		
837		/**
838		* Trigger the relevant event handler
839		* The handlers are passed the original event, the element that was swiped, and in the case of the catch all handler, the direction that was swiped, "left", "right", "up", or "down"
840		* @param {object} event the original event object
841		* @param {string} phase the phase of the swipe (start, end cancel etc) {@link $.fn.swipe.phases}
842		* @inner
843		*/
844		function triggerHandler(event, phase) {
845			
846			var ret = undefined;
847			
848			// SWIPE GESTURES
849			if(didSwipe() || hasSwipes()) { //hasSwipes as status needs to fire even if swipe is invalid
850				//Trigger the swipe events...
851				ret = triggerHandlerForGesture(event, phase, SWIPE);
852			} 
853			
854			// PINCH GESTURES (if the above didnt cancel)
855			else if((didPinch() || hasPinches()) && ret!==false) {
856				//Trigger the pinch events...
857				ret = triggerHandlerForGesture(event, phase, PINCH);
858			}
859			
860			// CLICK / TAP (if the above didnt cancel)
861			if(didDoubleTap() && ret!==false) {
862				//Trigger the tap events...
863				ret = triggerHandlerForGesture(event, phase, DOUBLE_TAP);
864			}
865			
866			// CLICK / TAP (if the above didnt cancel)
867			else if(didLongTap() && ret!==false) {
868				//Trigger the tap events...
869				ret = triggerHandlerForGesture(event, phase, LONG_TAP);
870			}
871
872			// CLICK / TAP (if the above didnt cancel)
873			else if(didTap() && ret!==false) {
874				//Trigger the tap event..
875				ret = triggerHandlerForGesture(event, phase, TAP);
876	    	}
877			
878			
879			
880			// If we are cancelling the gesture, then manually trigger the reset handler
881			if (phase === PHASE_CANCEL) {
882				touchCancel(event);
883			}
884			
885			// If we are ending the gesture, then manually trigger the reset handler IF all fingers are off
886			if(phase === PHASE_END) {
887				//If we support touch, then check that all fingers are off before we cancel
888				if (SUPPORTS_TOUCH) {
889					if(event.touches.length==0) {
890						touchCancel(event);	
891					}
892				} 
893				else {
894					touchCancel(event);
895				}
896			}
897					
898			return ret;
899		}
900		
901		
902		
903		/**
904		* Trigger the relevant event handler
905		* The handlers are passed the original event, the element that was swiped, and in the case of the catch all handler, the direction that was swiped, "left", "right", "up", or "down"
906		* @param {object} event the original event object
907		* @param {string} phase the phase of the swipe (start, end cancel etc) {@link $.fn.swipe.phases}
908		* @param {string} gesture the gesture to triger a handler for : PINCH or SWIPE {@link $.fn.swipe.gestures}
909		* @return Boolean False, to indicate that the event should stop propagation, or void.
910		* @inner
911		*/
912		function triggerHandlerForGesture(event, phase, gesture) {	
913			
914			var ret=undefined;
915			
916			//SWIPES....
917			if(gesture==SWIPE) {
918				//Trigger status every time..
919				
920				//Trigger the event...
921				$element.trigger('swipeStatus', [phase, direction || null, distance || 0, duration || 0, fingerCount]);
922				
923				//Fire the callback
924				if (options.swipeStatus) {
925					ret = options.swipeStatus.call($element, event, phase, direction || null, distance || 0, duration || 0, fingerCount);
926					//If the status cancels, then dont run the subsequent event handlers..
927					if(ret===false) return false;
928				}
929				
930				
931				
932				
933				if (phase == PHASE_END && validateSwipe()) {
vendor: 16,516 bytes, lines 934-1488
934					//Fire the catch all event
935					$element.trigger('swipe', [direction, distance, duration, fingerCount]);
936					
937					//Fire catch all callback
938					if (options.swipe) {
939						ret = options.swipe.call($element, event, direction, distance, duration, fingerCount);
940						//If the status cancels, then dont run the subsequent event handlers..
941						if(ret===false) return false;
942					}
943					
944					//trigger direction specific event handlers	
945					switch (direction) {
946						case LEFT:
947							//Trigger the event
948							$element.trigger('swipeLeft', [direction, distance, duration, fingerCount]);
949					
950					        //Fire the callback
951							if (options.swipeLeft) {
952								ret = options.swipeLeft.call($element, event, direction, distance, duration, fingerCount);
953							}
954							break;
955	
956						case RIGHT:
957							//Trigger the event
958					        $element.trigger('swipeRight', [direction, distance, duration, fingerCount]);
959					
960					        //Fire the callback
961							if (options.swipeRight) {
962								ret = options.swipeRight.call($element, event, direction, distance, duration, fingerCount);
963							}
964							break;
965	
966						case UP:
967							//Trigger the event
968					        $element.trigger('swipeUp', [direction, distance, duration, fingerCount]);
969					
970					        //Fire the callback
971							if (options.swipeUp) {
972								ret = options.swipeUp.call($element, event, direction, distance, duration, fingerCount);
973							}
974							break;
975	
976						case DOWN:
977							//Trigger the event
978					        $element.trigger('swipeDown', [direction, distance, duration, fingerCount]);
979					
980					        //Fire the callback
981							if (options.swipeDown) {
982								ret = options.swipeDown.call($element, event, direction, distance, duration, fingerCount);
983							}
984							break;
985					}
986				}
987			}
988			
989			
990			//PINCHES....
991			if(gesture==PINCH) {
992				//Trigger the event
993			     $element.trigger('pinchStatus', [phase, pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom]);
994					
995                //Fire the callback
996				if (options.pinchStatus) {
997					ret = options.pinchStatus.call($element, event, phase, pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom);
998					//If the status cancels, then dont run the subsequent event handlers..
999					if(ret===false) return false;
1000				}
1001				
1002				if(phase==PHASE_END && validatePinch()) {
1003					
1004					switch (pinchDirection) {
1005						case IN:
1006							//Trigger the event
1007                            $element.trigger('pinchIn', [pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom]);
1008                    
1009                            //Fire the callback
1010                            if (options.pinchIn) {
1011								ret = options.pinchIn.call($element, event, pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom);
1012							}
1013							break;
1014						
1015						case OUT:
1016							//Trigger the event
1017                            $element.trigger('pinchOut', [pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom]);
1018                    
1019                            //Fire the callback
1020                            if (options.pinchOut) {
1021								ret = options.pinchOut.call($element, event, pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom);
1022							}
1023							break;	
1024					}
1025				}
1026			}
1027			
1028
1029
1030                
1031	    		
1032			if(gesture==TAP) {
1033				if(phase === PHASE_CANCEL || phase === PHASE_END) {
1034					
1035    			    
1036    			    //Cancel any existing double tap
1037				    clearTimeout(singleTapTimeout);
1038				           
1039					//If we are also looking for doubelTaps, wait incase this is one...
1040				    if(hasDoubleTap() && !inDoubleTap()) {
1041				        //Cache the time of this tap
1042                        doubleTapStartTime = getTimeStamp();
1043                       
1044				        //Now wait for the double tap timeout, and trigger this single tap
1045				        //if its not cancelled by a double tap
1046				        singleTapTimeout = setTimeout($.proxy(function() {
1047        			        doubleTapStartTime=null;
1048        			        //Trigger the event
1049                            $element.trigger('tap', [event.target]);
1050
1051                        
1052                            //Fire the callback
1053                            if(options.tap) {
1054                                ret = options.tap.call($element, event, event.target);
1055                            }
1056    			        }, this), options.doubleTapThreshold );
1057    			    	
1058    			    } else {
1059                        doubleTapStartTime=null;
1060                        
1061                        //Trigger the event
1062                        $element.trigger('tap', [event.target]);
1063
1064                        
1065                        //Fire the callback
1066                        if(options.tap) {
1067                            ret = options.tap.call($element, event, event.target);
1068                        }
1069	    		    }
1070	    		}
1071			}
1072			
1073			else if (gesture==DOUBLE_TAP) {
1074				if(phase === PHASE_CANCEL || phase === PHASE_END) {
1075					//Cancel any pending singletap 
1076				    clearTimeout(singleTapTimeout);
1077				    doubleTapStartTime=null;
1078				        
1079                    //Trigger the event
1080                    $element.trigger('doubletap', [event.target]);
1081                
1082                    //Fire the callback
1083                    if(options.doubleTap) {
1084                        ret = options.doubleTap.call($element, event, event.target);
1085                    }
1086	    		}
1087			}
1088			
1089			else if (gesture==LONG_TAP) {
1090				if(phase === PHASE_CANCEL || phase === PHASE_END) {
1091					//Cancel any pending singletap (shouldnt be one)
1092				    clearTimeout(singleTapTimeout);
1093				    doubleTapStartTime=null;
1094				        
1095                    //Trigger the event
1096                    $element.trigger('longtap', [event.target]);
1097                
1098                    //Fire the callback
1099                    if(options.longTap) {
1100                        ret = options.longTap.call($element, event, event.target);
1101                    }
1102	    		}
1103			}				
1104				
1105			return ret;
1106		}
1107
1108
1109
1110		
1111		//
1112		// GESTURE VALIDATION
1113		//
1114		
1115		/**
1116		* Checks the user has swipe far enough
1117		* @return Boolean if <code>threshold</code> has been set, return true if the threshold was met, else false.
1118		* If no threshold was set, then we return true.
1119		* @inner
1120		*/
1121		function validateSwipeDistance() {
1122			var valid = true;
1123			//If we made it past the min swipe distance..
1124			if (options.threshold !== null) {
1125				valid = distance >= options.threshold;
1126			}
1127			
1128            return valid;
1129		}
1130		
1131		/**
1132		* Checks the user has swiped back to cancel.
1133		* @return Boolean if <code>cancelThreshold</code> has been set, return true if the cancelThreshold was met, else false.
1134		* If no cancelThreshold was set, then we return true.
1135		* @inner
1136		*/
1137		function didSwipeBackToCancel() {
1138            var cancelled = false;
1139    		if(options.cancelThreshold !== null && direction !==null)  {
1140    		    cancelled =  (getMaxDistance( direction ) - distance) >= options.cancelThreshold;
1141			}
1142			
1143			return cancelled;
1144		}
1145
1146		/**
1147		* Checks the user has pinched far enough
1148		* @return Boolean if <code>pinchThreshold</code> has been set, return true if the threshold was met, else false.
1149		* If no threshold was set, then we return true.
1150		* @inner
1151		*/
1152		function validatePinchDistance() {
1153			if (options.pinchThreshold !== null) {
1154				return pinchDistance >= options.pinchThreshold;
1155			}
1156			return true;
1157		}
1158
1159		/**
1160		* Checks that the time taken to swipe meets the minimum / maximum requirements
1161		* @return Boolean
1162		* @inner
1163		*/
1164		function validateSwipeTime() {
1165			var result;
1166			//If no time set, then return true
1167
1168			if (options.maxTimeThreshold) {
1169				if (duration >= options.maxTimeThreshold) {
1170					result = false;
1171				} else {
1172					result = true;
1173				}
1174			}
1175			else {
1176				result = true;
1177			}
1178
1179			return result;
1180		}
1181
1182
1183		/**
1184		* Checks direction of the swipe and the value allowPageScroll to see if we should allow or prevent the default behaviour from occurring.
1185		* This will essentially allow page scrolling or not when the user is swiping on a touchSwipe object.
1186		* @param {object} jqEvent The normalised jQuery representation of the event object.
1187		* @param {string} direction The direction of the event. See {@link $.fn.swipe.directions}
1188		* @see $.fn.swipe.directions
1189		* @inner
1190		*/
1191		function validateDefaultEvent(jqEvent, direction) {
1192			if (options.allowPageScroll === NONE || hasPinches()) {
1193				jqEvent.preventDefault();
1194			} else {
1195				var auto = options.allowPageScroll === AUTO;
1196
1197				switch (direction) {
1198					case LEFT:
1199						if ((options.swipeLeft && auto) || (!auto && options.allowPageScroll != HORIZONTAL)) {
1200							jqEvent.preventDefault();
1201						}
1202						break;
1203
1204					case RIGHT:
1205						if ((options.swipeRight && auto) || (!auto && options.allowPageScroll != HORIZONTAL)) {
1206							jqEvent.preventDefault();
1207						}
1208						break;
1209
1210					case UP:
1211						if ((options.swipeUp && auto) || (!auto && options.allowPageScroll != VERTICAL)) {
1212							jqEvent.preventDefault();
1213						}
1214						break;
1215
1216					case DOWN:
1217						if ((options.swipeDown && auto) || (!auto && options.allowPageScroll != VERTICAL)) {
1218							jqEvent.preventDefault();
1219						}
1220						break;
1221				}
1222			}
1223
1224		}
1225
1226
1227		// PINCHES
1228		/**
1229		 * Returns true of the current pinch meets the thresholds
1230		 * @return Boolean
1231		 * @inner
1232		*/
1233		function validatePinch() {
1234		    var hasCorrectFingerCount = validateFingers();
1235		    var hasEndPoint = validateEndPoint();
1236			var hasCorrectDistance = validatePinchDistance();
1237			return hasCorrectFingerCount && hasEndPoint && hasCorrectDistance;
1238			
1239		}
1240		
1241		/**
1242		 * Returns true if any Pinch events have been registered
1243		 * @return Boolean
1244		 * @inner
1245		*/
1246		function hasPinches() {
1247			//Enure we dont return 0 or null for false values
1248			return !!(options.pinchStatus || options.pinchIn || options.pinchOut);
1249		}
1250		
1251		/**
1252		 * Returns true if we are detecting pinches, and have one
1253		 * @return Boolean
1254		 * @inner
1255		 */
1256		function didPinch() {
1257			//Enure we dont return 0 or null for false values
1258			return !!(validatePinch() && hasPinches());
1259		}
1260
1261
1262
1263
1264		// SWIPES
1265		/**
1266		 * Returns true if the current swipe meets the thresholds
1267		 * @return Boolean
1268		 * @inner
1269		*/
1270		function validateSwipe() {
1271			//Check validity of swipe
1272			var hasValidTime = validateSwipeTime();
1273			var hasValidDistance = validateSwipeDistance();	
1274			var hasCorrectFingerCount = validateFingers();
1275		    var hasEndPoint = validateEndPoint();
1276		    var didCancel = didSwipeBackToCancel();	
1277		    
1278			// if the user swiped more than the minimum length, perform the appropriate action
1279			// hasValidDistance is null when no distance is set 
1280			var valid =  !didCancel && hasEndPoint && hasCorrectFingerCount && hasValidDistance && hasValidTime;
1281			
1282			return valid;
1283		}
1284		
1285		/**
1286		 * Returns true if any Swipe events have been registered
1287		 * @return Boolean
1288		 * @inner
1289		*/
1290		function hasSwipes() {
1291			//Enure we dont return 0 or null for false values
1292			return !!(options.swipe || options.swipeStatus || options.swipeLeft || options.swipeRight || options.swipeUp || options.swipeDown);
1293		}
1294		
1295		
1296		/**
1297		 * Returns true if we are detecting swipes and have one
1298		 * @return Boolean
1299		 * @inner
1300		*/
1301		function didSwipe() {
1302			//Enure we dont return 0 or null for false values
1303			return !!(validateSwipe() && hasSwipes());
1304		}
1305
1306        /**
1307		 * Returns true if we have matched the number of fingers we are looking for
1308		 * @return Boolean
1309		 * @inner
1310		*/
1311        function validateFingers() {
1312            //The number of fingers we want were matched, or on desktop we ignore
1313    		return ((fingerCount === options.fingers || options.fingers === ALL_FINGERS) || !SUPPORTS_TOUCH);
1314    	}
1315        
1316        /**
1317		 * Returns true if we have an end point for the swipe
1318		 * @return Boolean
1319		 * @inner
1320		*/
1321        function validateEndPoint() {
1322            //We have an end value for the finger
1323		    return fingerData[0].end.x !== 0;
1324        }
1325
1326		// TAP / CLICK
1327		/**
1328		 * Returns true if a click / tap events have been registered
1329		 * @return Boolean
1330		 * @inner
1331		*/
1332		function hasTap() {
1333			//Enure we dont return 0 or null for false values
1334			return !!(options.tap) ;
1335		}
1336		
1337		/**
1338		 * Returns true if a double tap events have been registered
1339		 * @return Boolean
1340		 * @inner
1341		*/
1342		function hasDoubleTap() {
1343			//Enure we dont return 0 or null for false values
1344			return !!(options.doubleTap) ;
1345		}
1346		
1347		/**
1348		 * Returns true if any long tap events have been registered
1349		 * @return Boolean
1350		 * @inner
1351		*/
1352		function hasLongTap() {
1353			//Enure we dont return 0 or null for false values
1354			return !!(options.longTap) ;
1355		}
1356		
1357		/**
1358		 * Returns true if we could be in the process of a double tap (one tap has occurred, we are listening for double taps, and the threshold hasn't past.
1359		 * @return Boolean
1360		 * @inner
1361		*/
1362		function validateDoubleTap() {
1363		    if(doubleTapStartTime==null){
1364		        return false;
1365		    }
1366		    var now = getTimeStamp();
1367		    return (hasDoubleTap() && ((now-doubleTapStartTime) <= options.doubleTapThreshold));
1368		}
1369		
1370		/**
1371		 * Returns true if we could be in the process of a double tap (one tap has occurred, we are listening for double taps, and the threshold hasn't past.
1372		 * @return Boolean
1373		 * @inner
1374		*/
1375		function inDoubleTap() {
1376		    return validateDoubleTap();
1377		}
1378		
1379		
1380		/**
1381		 * Returns true if we have a valid tap
1382		 * @return Boolean
1383		 * @inner
1384		*/
1385		function validateTap() {
1386		    return ((fingerCount === 1 || !SUPPORTS_TOUCH) && (isNaN(distance) || distance === 0));
1387		}
1388		
1389		/**
1390		 * Returns true if we have a valid long tap
1391		 * @return Boolean
1392		 * @inner
1393		*/
1394		function validateLongTap() {
1395		    //slight threshold on moving finger
1396            return ((duration > options.longTapThreshold) && (distance < DOUBLE_TAP_THRESHOLD)); 
1397		}
1398		
1399		/**
1400		 * Returns true if we are detecting taps and have one
1401		 * @return Boolean
1402		 * @inner
1403		*/
1404		function didTap() {
1405		    //Enure we dont return 0 or null for false values
1406			return !!(validateTap() && hasTap());
1407		}
1408		
1409		
1410		/**
1411		 * Returns true if we are detecting double taps and have one
1412		 * @return Boolean
1413		 * @inner
1414		*/
1415		function didDoubleTap() {
1416		    //Enure we dont return 0 or null for false values
1417			return !!(validateDoubleTap() && hasDoubleTap());
1418		}
1419		
1420		/**
1421		 * Returns true if we are detecting long taps and have one
1422		 * @return Boolean
1423		 * @inner
1424		*/
1425		function didLongTap() {
1426		    //Enure we dont return 0 or null for false values
1427			return !!(validateLongTap() && hasLongTap());
1428		}
1429		
1430		
1431		
1432		
1433		// MULTI FINGER TOUCH
1434		/**
1435		 * Starts tracking the time between 2 finger releases, and keeps track of how many fingers we initially had up
1436		 * @inner
1437		*/
1438		function startMultiFingerRelease() {
1439			previousTouchEndTime = getTimeStamp();
1440			previousTouchFingerCount = event.touches.length+1;
1441		}
1442		
1443		/**
1444		 * Cancels the tracking of time between 2 finger releases, and resets counters
1445		 * @inner
1446		*/
1447		function cancelMultiFingerRelease() {
1448			previousTouchEndTime = 0;
1449			previousTouchFingerCount = 0;
1450		}
1451		
1452		/**
1453		 * Checks if we are in the threshold between 2 fingers being released 
1454		 * @return Boolean
1455		 * @inner
1456		*/
1457		function inMultiFingerRelease() {
1458			
1459			var withinThreshold = false;
1460			
1461			if(previousTouchEndTime) {	
1462				var diff = getTimeStamp() - previousTouchEndTime	
1463				if( diff<=options.fingerReleaseThreshold ) {
1464					withinThreshold = true;
1465				}
1466			}
1467			
1468			return withinThreshold;	
1469		}
1470		
1471
1472		/**
1473		* gets a data flag to indicate that a touch is in progress
1474		* @return Boolean
1475		* @inner
1476		*/
1477		function getTouchInProgress() {
1478			//strict equality to ensure only true and false are returned
1479			return !!($element.data(PLUGIN_NS+'_intouch') === true);
1480		}
1481		
1482		/**
1483		* Sets a data flag to indicate that a touch is in progress
1484		* @param {boolean} val The value to set the property to
1485		* @inner
1486		*/
1487		function setTouchInProgress(val) {
1488			
1489			//Add or remove event listeners depending on touch status
1490			if(val===true) {
1491				$element.bind(MOVE_EV, touchMove);
1492				$element.bind(END_EV, touchEnd);
1493				
1494				//we only have leave events on desktop, we manually calcuate leave on touch as its not supported in webkit
1495				if(LEAVE_EV) { 
1496					$element.bind(LEAVE_EV, touchLeave);
1497				}
1498			} else {
1499				$element.unbind(MOVE_EV, touchMove, false);
1500				$element.unbind(END_EV, touchEnd, false);
1501			
1502				//we only have leave events on desktop, we manually calcuate leave on touch as its not supported in webkit
1503				if(LEAVE_EV) { 
1504					$element.unbind(LEAVE_EV, touchLeave, false);
1505				}
1506			}
1507			
1508		
1509			//strict equality to ensure only true and false can update the value
1510			$element.data(PLUGIN_NS+'_intouch', val === true);
1511		}
1512		
1513		
1514		/**
1515		 * Creates the finger data for the touch/finger in the event object.
1516		 * @param {int} index The index in the array to store the finger data (usually the order the fingers were pressed)
1517		 * @param {object} evt The event object containing finger data
1518		 * @return finger data object
1519		 * @inner
1520		*/
1521		function createFingerData( index, evt ) {
1522			var id = evt.identifier!==undefined ? evt.identifier : 0; 
1523			
1524			fingerData[index].identifier = id;
1525			fingerData[index].start.x = fingerData[index].end.x = evt.pageX||evt.clientX;
1526			fingerData[index].start.y = fingerData[index].end.y = evt.pageY||evt.clientY;
1527			
1528			return fingerData[index];
1529		}
1530		
1531		/**
1532		 * Updates the finger data for a particular event object
1533		 * @param {object} evt The event object containing the touch/finger data to upadte
1534		 * @return a finger data object.
1535		 * @inner
1536		*/
1537		function updateFingerData(evt) {
1538			
1539			var id = evt.identifier!==undefined ? evt.identifier : 0; 
1540			var f = getFingerData( id );
1541			
1542			f.end.x = evt.pageX||evt.clientX;
1543			f.end.y = evt.pageY||evt.clientY;
1544			
1545			return f;
1546		}
1547		
1548		/**
1549		 * Returns a finger data object by its event ID.
1550		 * Each touch event has an identifier property, which is used 
1551		 * to track repeat touches
1552		 * @param {int} id The unique id of the finger in the sequence of touch events.
1553		 * @return a finger data object.
1554		 * @inner
1555		*/
1556		function getFingerData( id ) {
1557			for(var i=0; i<fingerData.length; i++) {
1558				if(fingerData[i].identifier == id) {
1559					return fingerData[i];	
1560				}
1561			}
1562		}
1563		
1564		/**
1565		 * Creats all the finger onjects and returns an array of finger data
1566		 * @return Array of finger objects
1567		 * @inner
1568		*/
1569		function createAllFingerData() {
1570			var fingerData=[];
1571			for (var i=0; i<=5; i++) {
1572				fingerData.push({
1573					start:{ x: 0, y: 0 },
1574					end:{ x: 0, y: 0 },
1575					identifier:0
1576				});
1577			}
1578			
1579			return fingerData;
1580		}
1581		
1582		/**
1583		 * Sets the maximum distance swiped in the given direction. 
1584		 * If the new value is lower than the current value, the max value is not changed.
1585		 * @param {string}  direction The direction of the swipe
1586		 * @param {int}  distance The distance of the swipe
1587		 * @inner
1588		*/
1589		function setMaxDistance(direction, distance) {
1590    		distance = Math.max(distance, getMaxDistance(direction) );
1591    		maximumsMap[direction].distance = distance;
1592		}
1593        
1594        /**
1595		 * gets the maximum distance swiped in the given direction. 
1596		 * @param {string}  direction The direction of the swipe
1597		 * @return int  The distance of the swipe
1598		 * @inner
1599		*/        
1600        function getMaxDistance(direction) {
1601            return maximumsMap[direction].distance;
1602        }
1603		
1604		/**
1605		 * Creats a map of directions to maximum swiped values.
1606		 * @return Object A dictionary of maximum values, indexed by direction.
1607		 * @inner
1608		*/
1609		function createMaximumsData() {
1610			var maxData={};
1611			maxData[LEFT]=createMaximumVO(LEFT);
1612			maxData[RIGHT]=createMaximumVO(RIGHT);
1613			maxData[UP]=createMaximumVO(UP);
1614			maxData[DOWN]=createMaximumVO(DOWN);
1615			
1616			return maxData;
1617		}
1618		
1619		/**
1620		 * Creates a map maximum swiped values for a given swipe direction
1621		 * @param {string} The direction that these values will be associated with
1622		 * @return Object Maximum values
1623		 * @inner
1624		*/
1625		function createMaximumVO(dir) {
1626		    return { 
1627		        direction:dir, 
1628		        distance:0
1629		    }
1630		}
1631		
1632		
1633		//
1634		// MATHS / UTILS
1635		//
1636
1637		/**
1638		* Calculate the duration of the swipe
1639		* @return int
1640		* @inner
1641		*/
1642		function calculateDuration() {
1643			return endTime - startTime;
1644		}
1645		
1646		/**
1647		* Calculate the distance between 2 touches (pinch)
1648		* @param {point}
vendor: 4,121 bytes, lines 1648-1784
1648 startPoint A point object containing x and y co-ordinates
1649	    * @param {point} endPoint A point object containing x and y co-ordinates
1650	    * @return int;
1651		* @inner
1652		*/
1653		function calculateTouchesDistance(startPoint, endPoint) {
1654			var diffX = Math.abs(startPoint.x - endPoint.x);
1655			var diffY = Math.abs(startPoint.y - endPoint.y);
1656				
1657			return Math.round(Math.sqrt(diffX*diffX+diffY*diffY));
1658		}
1659		
1660		/**
1661		* Calculate the zoom factor between the start and end distances
1662		* @param {int} startDistance Distance (between 2 fingers) the user started pinching at
1663	    * @param {int} endDistance Distance (between 2 fingers) the user ended pinching at
1664	    * @return float The zoom value from 0 to 1.
1665		* @inner
1666		*/
1667		function calculatePinchZoom(startDistance, endDistance) {
1668			var percent = (endDistance/startDistance) * 1;
1669			return percent.toFixed(2);
1670		}
1671		
1672		
1673		/**
1674		* Returns the pinch direction, either IN or OUT for the given points
1675		* @return string Either {@link $.fn.swipe.directions.IN} or {@link $.fn.swipe.directions.OUT}
1676		* @see $.fn.swipe.directions
1677		* @inner
1678		*/
1679		function calculatePinchDirection() {
1680			if(pinchZoom<1) {
1681				return OUT;
1682			}
1683			else {
1684				return IN;
1685			}
1686		}
1687		
1688		
1689		/**
1690		* Calculate the length / distance of the swipe
1691		* @param {point} startPoint A point object containing x and y co-ordinates
1692	    * @param {point} endPoint A point object containing x and y co-ordinates
1693	    * @return int
1694		* @inner
1695		*/
1696		function calculateDistance(startPoint, endPoint) {
1697			return Math.round(Math.sqrt(Math.pow(endPoint.x - startPoint.x, 2) + Math.pow(endPoint.y - startPoint.y, 2)));
1698		}
1699
1700		/**
1701		* Calculate the angle of the swipe
1702		* @param {point} startPoint A point object containing x and y co-ordinates
1703	    * @param {point} endPoint A point object containing x and y co-ordinates
1704	    * @return int
1705		* @inner
1706		*/
1707		function calculateAngle(startPoint, endPoint) {
1708			var x = startPoint.x - endPoint.x;
1709			var y = endPoint.y - startPoint.y;
1710			var r = Math.atan2(y, x); //radians
1711			var angle = Math.round(r * 180 / Math.PI); //degrees
1712
1713			//ensure value is positive
1714			if (angle < 0) {
1715				angle = 360 - Math.abs(angle);
1716			}
1717
1718			return angle;
1719		}
1720
1721		/**
1722		* Calculate the direction of the swipe
1723		* This will also call calculateAngle to get the latest angle of swipe
1724		* @param {point} startPoint A point object containing x and y co-ordinates
1725	    * @param {point} endPoint A point object containing x and y co-ordinates
1726	    * @return string Either {@link $.fn.swipe.directions.LEFT} / {@link $.fn.swipe.directions.RIGHT} / {@link $.fn.swipe.directions.DOWN} / {@link $.fn.swipe.directions.UP}
1727		* @see $.fn.swipe.directions
1728		* @inner
1729		*/
1730		function calculateDirection(startPoint, endPoint ) {
1731			var angle = calculateAngle(startPoint, endPoint);
1732
1733			if ((angle <= 45) && (angle >= 0)) {
1734				return LEFT;
1735			} else if ((angle <= 360) && (angle >= 315)) {
1736				return LEFT;
1737			} else if ((angle >= 135) && (angle <= 225)) {
1738				return RIGHT;
1739			} else if ((angle > 45) && (angle < 135)) {
1740				return DOWN;
1741			} else {
1742				return UP;
1743			}
1744		}
1745		
1746
1747		/**
1748		* Returns a MS time stamp of the current time
1749		* @return int
1750		* @inner
1751		*/
1752		function getTimeStamp() {
1753			var now = new Date();
1754			return now.getTime();
1755		}
1756		
1757		
1758		
1759		/**
1760		 * Returns a bounds object with left, right, top and bottom properties for the element specified.
1761		 * @param {DomNode} The DOM node to get the bounds for.
1762		 */
1763		function getbounds( el ) {
1764			el = $(el);
1765			var offset = el.offset();
1766			
1767			var bounds = {	
1768					left:offset.left,
1769					right:offset.left+el.outerWidth(),
1770					top:offset.top,
1771					bottom:offset.top+el.outerHeight()
1772					}
1773			
1774			return bounds;	
1775		}
1776		
1777		
1778		/**
1779		 * Checks if the point object is in the bounds object.
1780		 * @param {object} point A point object.
1781		 * @param {int} point.x The x value of the point.
1782		 * @param {int} point.y The x value of the point.
1783		 * @param {object} bounds The bounds object to test
1784		 * @param {int}
1784 bounds.left The leftmost value
1785		 * @param {int} bounds.right The righttmost value
1786		 * @param {int} bounds.top The topmost value
1787		* @param {int} bounds.bottom The bottommost value
1788		 */
1789		function isInBounds(point, bounds) {
1790			return (point.x > bounds.left && point.x < bounds.right && point.y > bounds.top && point.y < bounds.bottom);
1791		};
1792	
1793	
1794	}
1795	
1796	
1797
1798
1799/**
1800 * A catch all handler that is triggered for all swipe directions. 
1801 * @name $.fn.swipe#swipe
1802 * @event
1803 * @default null
1804 * @param {EventObject} event The original event object
1805 * @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
1806 * @param {int} distance The distance the user swiped
1807 * @param {int} duration The duration of the swipe in milliseconds
1808 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1809 */
1810 
1811
1812
1813
1814/**
1815 * A handler that is triggered for "left" swipes.
1816 * @name $.fn.swipe#swipeLeft
1817 * @event
1818 * @default null
1819 * @param {EventObject} event The original event object
1820 * @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
1821 * @param {int} distance The distance the user swiped
1822 * @param {int} duration The duration of the swipe in milliseconds
1823 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1824 */
1825 
1826/**
1827 * A handler that is triggered for "right" swipes.
1828 * @name $.fn.swipe#swipeRight
1829 * @event
1830 * @default null
1831 * @param {EventObject} event The original event object
1832 * @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
1833 * @param {int} distance The distance the user swiped
1834 * @param {int} duration The duration of the swipe in milliseconds
1835 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1836 */
1837
1838/**
1839 * A handler that is triggered for "up" swipes.
1840 * @name $.fn.swipe#swipeUp
1841 * @event
1842 * @default null
1843 * @param {EventObject} event The original event object
1844 * @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
1845 * @param {int} distance The distance the user swiped
1846 * @param {int} duration The duration of the swipe in milliseconds
1847 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1848 */
1849 
1850/**
1851 * A handler that is triggered for "down" swipes.
1852 * @name $.fn.swipe#swipeDown
1853 * @event
1854 * @default null
1855 * @param {EventObject} event The original event object
1856 * @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
1857 * @param {int} distance The distance the user swiped
1858 * @param {int} duration The duration of the swipe in milliseconds
1859 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1860 */
1861 
1862/**
1863 * A handler triggered for every phase of the swipe. This handler is constantly fired for the duration of the pinch.
1864 * This is triggered regardless of swipe thresholds.
1865 * @name $.fn.swipe#swipeStatus
1866 * @event
1867 * @default null
1868 * @param {EventObject} event The original event object
1869 * @param {string} phase The phase of the swipe event. See {@link $.fn.swipe.phases}
1870 * @param {string} direction The direction the user swiped in. This is null if the user has yet to move. See {@link $.fn.swipe.directions}
1871 * @param {int} distance The distance the user swiped. This is 0 if the user has yet to move.
1872 * @param {int} duration The duration of the swipe in milliseconds
1873 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1874 */
1875 
1876/**
1877 * A handler triggered for pinch in events.
1878 * @name $.fn.swipe#pinchIn
1879 * @event
1880 * @default null
1881 * @param {EventObject} event The original event object
1882 * @param {int} direction The direction the user pinched in. See {@link $.fn.swipe.directions}
1883 * @param {int} distance The distance the user pinched
1884 * @param {int} duration The duration of the swipe in milliseconds
1885 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1886 * @param {int} zoom The zoom/scale level the user pinched too, 0-1.
1887 */
1888
1889/**
1890 * A handler triggered for pinch out events.
1891 * @name $.fn.swipe#pinchOut
1892 * @event
1893 * @default null
1894 * @param {EventObject} event The original event object
1895 * @param {int} direction The direction the user pinched in. See {@link $.fn.swipe.directions}
1896 * @param {int} distance The distance the user pinched
1897 * @param {int} duration The duration of the swipe in milliseconds
1898 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1899 * @param {int} zoom The zoom/scale level the user pinched too, 0-1.
1900 */ 
1901
1902/**
1903 * A handler triggered for all pinch events. This handler is constantly f
1903ired for the duration of the pinch. This is triggered regardless of thresholds.
1904 * @name $.fn.swipe#pinchStatus
1905 * @event
1906 * @default null
1907 * @param {EventObject} event The original event object
1908 * @param {int} direction The direction the user pinched in. See {@link $.fn.swipe.directions}
1909 * @param {int} distance The distance the user pinched
1910 * @param {int} duration The duration of the swipe in milliseconds
1911 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1912 * @param {int} zoom The zoom/scale level the user pinched too, 0-1.
1913 */
1914
1915/**
1916 * A click handler triggered when a user simply clicks, rather than swipes on an element.
1917 * This is deprecated since version 1.6.2, any assignment to click will be assigned to the tap handler.
1918 * You cannot use <code>on</code> to bind to this event as the default jQ <code>click</code> event will be triggered.
1919 * Use the <code>tap</code> event instead.
1920 * @name $.fn.swipe#click
1921 * @event
1922 * @deprecated since version 1.6.2, please use {@link $.fn.swipe#tap} instead 
1923 * @default null
1924 * @param {EventObject} event The original event object
1925 * @param {DomObject} target The element clicked on.
1926 */
1927 
1928 /**
1929 * A click / tap handler triggered when a user simply clicks or taps, rather than swipes on an element.
1930 * @name $.fn.swipe#tap
1931 * @event
1932 * @default null
1933 * @param {EventObject} event The original event object
1934 * @param {DomObject} target The element clicked on.
1935 */
1936 
1937/**
1938 * A double tap handler triggered when a user double clicks or taps on an element.
1939 * You can set the time delay for a double tap with the {@link $.fn.swipe.defaults#doubleTapThreshold} property. 
1940 * Note: If you set both <code>doubleTap</code> and <code>tap</code> handlers, the <code>tap</code> event will be delayed by the <code>doubleTapThreshold</code>
1941 * as the script needs to check if its a double tap.
1942 * @name $.fn.swipe#doubleTap
1943 * @see  $.fn.swipe.defaults#doubleTapThreshold
1944 * @event
1945 * @default null
1946 * @param {EventObject} event The original event object
1947 * @param {DomObject} target The element clicked on.
1948 */
1949 
1950 /**
1951 * A long tap handler triggered when a user long clicks or taps on an element.
1952 * You can set the time delay for a long tap with the {@link $.fn.swipe.defaults#longTapThreshold} property. 
1953 * @name $.fn.swipe#longTap
1954 * @see  $.fn.swipe.defaults#longTapThreshold
1955 * @event
1956 * @default null
1957 * @param {EventObject} event The original event object
1958 * @param {DomObject} target The element clicked on.
1959 */
1960
1961})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.