]>
git.immae.eu Git - perso/Immae/Projets/packagist/jquery-touchswipe.git/blob - jquery.touchSwipe.js
2 * @fileOverview TouchSwipe - jQuery Plugin
5 * @author Matt Bryson http://www.github.com/mattbryson
6 * @see https://github.com/mattbryson/TouchSwipe-Jquery-Plugin
7 * @see http://labs.rampinteractive.co.uk/touchSwipe/
8 * @see http://plugins.jquery.com/project/touchSwipe
10 * Copyright (c) 2010-2015 Matt Bryson
11 * Dual licensed under the MIT or GPL Version 2 licenses.
18 * $Date: 2010-12-12 (Wed, 12 Dec 2010) $
20 * $version: 1.0.1 - removed multibyte comments
22 * $Date: 2011-21-02 (Mon, 21 Feb 2011) $
23 * $version: 1.1.0 - added allowPageScroll property to allow swiping and scrolling of page
24 * - changed handler signatures so one handler can be used for multiple events
25 * $Date: 2011-23-02 (Wed, 23 Feb 2011) $
26 * $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.
27 * - 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.
28 * $version: 1.2.1 - removed console log!
30 * $version: 1.2.2 - Fixed bug where scope was not preserved in callback methods.
32 * $Date: 2011-28-04 (Thurs, 28 April 2011) $
33 * $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.
35 * $Date: 2011-27-09 (Tues, 27 September 2011) $
36 * $version: 1.2.5 - Added support for testing swipes with mouse on desktop browser (thanks to https://github.com/joelhy)
38 * $Date: 2012-14-05 (Mon, 14 May 2012) $
39 * $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
41 * $Date: 2012-05-06 (Tues, 05 June 2012) $
42 * $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.
44 * $Date: 2012-05-06 (Tues, 05 June 2012) $
45 * $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.
47 * $Date: 2012-06-06 (Wed, 06 June 2012) $
48 * $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
50 * $Date: 2012-05-06 (Fri, 05 June 2012) $
51 * $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.
53 * $Date: 2012-29-07 (Sun, 29 July 2012) $
54 * $version: 1.3.2 - Added fallbackToMouseEvents option to NOT capture mouse events on non touch devices.
55 * - Added "all" fingers value to the fingers property, so any combination of fingers triggers the swipe, allowing event handlers to check the finger count
57 * $Date: 2012-09-08 (Thurs, 9 Aug 2012) $
58 * $version: 1.3.3 - Code tidy prep for minefied version
60 * $Date: 2012-04-10 (wed, 4 Oct 2012) $
61 * $version: 1.4.0 - Added pinch support, pinchIn and pinchOut
63 * $Date: 2012-11-10 (Thurs, 11 Oct 2012) $
64 * $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.
66 * $Date: 2012-22-10 (Mon, 22 Oct 2012) $
67 * $version: 1.5.1 - Fixed bug with jQuery 1.8 and trailing comma in excludedElements
68 * - Fixed bug with IE and eventPreventDefault()
69 * $Date: 2013-01-12 (Fri, 12 Jan 2013) $
70 * $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.
71 * - made the demo site all static local HTML pages so they can be run locally by a developer
72 * - added jsDoc comments and added documentation for the plugin
74 * - added triggerOnTouchLeave property that will end the event when the user swipes off the element.
75 * $Date: 2013-03-23 (Sat, 23 Mar 2013) $
76 * $version: 1.6.1 - Added support for ie8 touch events
77 * $version: 1.6.2 - Added support for events binding with on / off / bind in jQ for all callback names.
78 * - Deprecated the 'click' handler in favour of tap.
79 * - added cancelThreshold property
80 * - added option method to update init options at runtime
81 * $version 1.6.3 - added doubletap, longtap events and longTapThreshold, doubleTapThreshold property
83 * $Date: 2013-04-04 (Thurs, 04 April 2013) $
84 * $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.
86 * $Date: 2013-08-24 (Sat, 24 Aug 2013) $
87 * $version 1.6.5 - Merged a few pull requests fixing various bugs, added AMD support.
89 * $Date: 2014-06-04 (Wed, 04 June 2014) $
90 * $version 1.6.6 - Merge of pull requests.
91 * - IE10 touch support
92 * - Only prevent default event handling on valid swipe
93 * - Separate license/changelog comment
94 * - Detect if the swipe is valid at the end of the touch event.
95 * - Pass fingerdata to event handlers.
96 * - Add 'hold' gesture
97 * - Be more tolerant about the tap distance
98 * - Typos and minor fixes
100 * $Date: 2015-22-01 (Thurs, 22 Jan 2015) $
101 * $version 1.6.7 - Added patch from https://github.com/mattbryson/TouchSwipe-Jquery-Plugin/issues/206 to fix memory leak
103 * $Date: 2015-2-2 (Mon, 2 Feb 2015) $
104 * $version 1.6.8 - Added preventDefaultEvents option to proxy events regardless.
105 * - Fixed issue with swipe and pinch not triggering at the same time
107 * $Date: 2015-9-6 (Tues, 9 June 2015) $
108 * $version 1.6.9 - Added PR from jdalton/hybrid to fix pointer events
109 * - Added scrolling demo
110 * - Added version property to plugin
112 * $Date: 2015-1-10 (Wed, 1 October 2015) $
113 * $version 1.6.10 - Added PR from beatspace to fix tap events
114 * $version 1.6.11 - Added PRs from indri-indri ( Doc tidyup), kkirsche ( Bower tidy up ), UziTech (preventDefaultEvents fixes )
115 * - Allowed setting multiple options via .swipe("options", options_hash) and more simply .swipe(options_hash) or exisitng instances
116 * $version 1.6.12 - Fixed bug with multi finger releases above 2 not triggering events
118 * $Date: 2015-12-18 (Fri, 18 December 2015) $
119 * $version 1.6.13 - Added PRs
120 * - Fixed #267 allowPageScroll not working correctly
121 * $version 1.6.14 - Fixed #220 / #248 doubletap not firing with swipes, #223 commonJS compatible
122 * $version 1.6.15 - More bug fixes
126 * See (http://jquery.com/).
129 * See the jQuery Library (http://jquery.com/) for full details. This just
130 * documents the function and classes that are added to jQuery by this plug-in.
134 * See (http://jquery.com/)
137 * See the jQuery Library (http://jquery.com/) for full details. This just
138 * documents the function and classes that are added to jQuery by this plug-in.
144 if ( typeof define
=== 'function' && define
. amd
&& define
. amd
. jQuery
) {
145 // AMD. Register as anonymous module.
146 define ([ 'jquery' ], factory
);
147 } else if ( typeof module
!== 'undefined' && module
. exports
) {
149 factory ( require ( "jquery" ));
158 var VERSION
= "1.6.15" ,
172 DOUBLE_TAP
= "doubletap" ,
173 LONG_TAP
= "longtap" ,
176 HORIZONTAL
= "horizontal" ,
177 VERTICAL
= "vertical" ,
181 DOUBLE_TAP_THRESHOLD
= 10 ,
183 PHASE_START
= "start" ,
186 PHASE_CANCEL
= "cancel" ,
188 SUPPORTS_TOUCH
= 'ontouchstart' in window
,
190 SUPPORTS_POINTER_IE10
= window
. navigator
. msPointerEnabled
&& ! window
. navigator
. pointerEnabled
&& ! SUPPORTS_TOUCH
,
192 SUPPORTS_POINTER
= ( window
. navigator
. pointerEnabled
|| window
. navigator
. msPointerEnabled
) && ! SUPPORTS_TOUCH
,
194 PLUGIN_NS
= 'TouchSwipe' ;
199 * The default configuration, and available options to configure touch swipe with.
200 * You can set the default values by updating any of the properties prior to instantiation.
201 * @name $.fn.swipe.defaults
203 * @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.
204 * @property {int} [threshold=75] The number of pixels that the user must move their finger by before it is considered a swipe.
205 * @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.
206 * @property {int} [pinchThreshold=20] The number of pixels that the user must pinch their finger by before it is considered a pinch.
207 * @property {int} [maxTimeThreshold=null] Time, in milliseconds, between touchStart and touchEnd must NOT exceed in order to be considered a swipe.
208 * @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.
209 * @property {int} [longTapThreshold=500] Time in milliseconds between tap and release for a long tap
210 * @property {int} [doubleTapThreshold=200] Time in milliseconds between 2 taps to count as a double tap
211 * @property {function} [swipe=null] A handler to catch all swipes. See {@link $.fn.swipe#event:swipe}
212 * @property {function} [swipeLeft=null] A handler that is triggered for "left" swipes. See {@link $.fn.swipe#event:swipeLeft}
213 * @property {function} [swipeRight=null] A handler that is triggered for "right" swipes. See {@link $.fn.swipe#event:swipeRight}
214 * @property {function} [swipeUp=null] A handler that is triggered for "up" swipes. See {@link $.fn.swipe#event:swipeUp}
215 * @property {function} [swipeDown=null] A handler that is triggered for "down" swipes. See {@link $.fn.swipe#event:swipeDown}
216 * @property {function} [swipeStatus=null] A handler triggered for every phase of the swipe. See {@link $.fn.swipe#event:swipeStatus}
217 * @property {function} [pinchIn=null] A handler triggered for pinch in events. See {@link $.fn.swipe#event:pinchIn}
218 * @property {function} [pinchOut=null] A handler triggered for pinch out events. See {@link $.fn.swipe#event:pinchOut}
219 * @property {function} [pinchStatus=null] A handler triggered for every phase of a pinch. See {@link $.fn.swipe#event:pinchStatus}
220 * @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.
221 * @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}
222 * @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#longTapThreshold}
223 * @property (function) [hold=null] A handler triggered when a user reaches longTapThreshold on the item. See {@link $.fn.swipe.defaults#longTapThreshold}
224 * @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.
225 * @property {boolean} [triggerOnTouchLeave=false] If true, then when the user leaves the swipe object, the swipe will end and trigger appropriate handlers.
226 * @property {string|undefined} [allowPageScroll='auto'] How the browser handles page scrolls when the user is swiping on a touchSwipe object. See {@link $.fn.swipe.pageScroll}. <br/><br/>
227 <code>"auto"</code> : all undefined swipes will cause the page to scroll in that direction. <br/>
228 <code>"none"</code> : the page will not scroll when user swipes. <br/>
229 <code>"horizontal"</code> : will force page to scroll on horizontal swipes. <br/>
230 <code>"vertical"</code> : will force page to scroll on vertical swipes. <br/>
231 * @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.
232 * @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.
233 * @property {boolean} [preventDefaultEvents=true] by default default events are cancelled, so the page doesn't move. You can dissable this so both native events fire as well as your handlers.
239 cancelThreshold : null ,
241 maxTimeThreshold : null ,
242 fingerReleaseThreshold : 250 ,
243 longTapThreshold : 500 ,
244 doubleTapThreshold : 200 ,
254 click : null , //Deprecated since 1.6.2
259 triggerOnTouchEnd : true ,
260 triggerOnTouchLeave : false ,
261 allowPageScroll : "auto" ,
262 fallbackToMouseEvents : true ,
263 excludedElements : "label, button, input, select, textarea, a, .noSwipe" ,
264 preventDefaultEvents : true
270 * Applies TouchSwipe behaviour to one or more jQuery objects.
271 * The TouchSwipe plugin can be instantiated via this method, or methods within
272 * TouchSwipe can be executed via this method as per jQuery plugin architecture.
273 * An existing plugin can have its options changed simply by re calling .swipe(options)
276 * @param {Mixed} method If the current DOMNode is a TouchSwipe object, and <code>method</code> is a TouchSwipe method, then
277 * the <code>method</code> is executed, and any following arguments are passed to the TouchSwipe method.
278 * If <code>method</code> is an object, then the TouchSwipe class is instantiated on the current DOMNode, passing the
279 * configuration properties defined in the object. See TouchSwipe
282 $. fn
. swipe = function ( method
) {
284 plugin
= $ this . data ( PLUGIN_NS
);
286 //Check if we are already instantiated and trying to execute a method
287 if ( plugin
&& typeof method
=== 'string' ) {
288 if ( plugin
[ method
]) {
289 return plugin
[ method
]. apply ( this , Array
. prototype . slice
. call ( arguments
, 1 ));
291 $. error ( 'Method ' + method
+ ' does not exist on jQuery.swipe' );
295 //Else update existing plugin with new options hash
296 else if ( plugin
&& typeof method
=== 'object' ) {
297 plugin
[ 'option' ]. apply ( this , arguments
);
300 //Else not instantiated and trying to pass init object (or nothing)
301 else if (! plugin
&& ( typeof method
=== 'object' || ! method
)) {
302 return init
. apply ( this , arguments
);
309 * The version of the plugin
312 $. fn
. swipe
. version
= VERSION
;
316 //Expose our defaults so a user could override the plugin defaults
317 $. fn
. swipe
. defaults
= defaults
;
320 * The phases that a touch event goes through. The <code>phase</code> is passed to the event handlers.
321 * These properties are read only, attempting to change them will not alter the values passed to the event handlers.
324 * @property {string} PHASE_START Constant indicating the start phase of the touch event. Value is <code>"start"</code>.
325 * @property {string} PHASE_MOVE Constant indicating the move phase of the touch event. Value is <code>"move"</code>.
326 * @property {string} PHASE_END Constant indicating the end phase of the touch event. Value is <code>"end"</code>.
327 * @property {string} PHASE_CANCEL Constant indicating the cancel phase of the touch event. Value is <code>"cancel"</code>.
329 $. fn
. swipe
. phases
= {
330 PHASE_START : PHASE_START
,
331 PHASE_MOVE : PHASE_MOVE
,
332 PHASE_END : PHASE_END
,
333 PHASE_CANCEL : PHASE_CANCEL
337 * The direction constants that are passed to the event handlers.
338 * These properties are read only, attempting to change them will not alter the values passed to the event handlers.
341 * @property {string} LEFT Constant indicating the left direction. Value is <code>"left"</code>.
342 * @property {string} RIGHT Constant indicating the right direction. Value is <code>"right"</code>.
343 * @property {string} UP Constant indicating the up direction. Value is <code>"up"</code>.
344 * @property {string} DOWN Constant indicating the down direction. Value is <code>"cancel"</code>.
345 * @property {string} IN Constant indicating the in direction. Value is <code>"in"</code>.
346 * @property {string} OUT Constant indicating the out direction. Value is <code>"out"</code>.
348 $. fn
. swipe
. directions
= {
358 * The page scroll constants that can be used to set the value of <code>allowPageScroll</code> option
359 * These properties are read only
362 * @see $.fn.swipe.defaults#allowPageScroll
363 * @property {string} NONE Constant indicating no page scrolling is allowed. Value is <code>"none"</code>.
364 * @property {string} HORIZONTAL Constant indicating horizontal page scrolling is allowed. Value is <code>"horizontal"</code>.
365 * @property {string} VERTICAL Constant indicating vertical page scrolling is allowed. Value is <code>"vertical"</code>.
366 * @property {string} AUTO Constant indicating either horizontal or vertical will be allowed, depending on the swipe handlers registered. Value is <code>"auto"</code>.
368 $. fn
. swipe
. pageScroll
= {
370 HORIZONTAL : HORIZONTAL
,
376 * Constants representing the number of fingers used in a swipe. These are used to set both the value of <code>fingers</code> in the
377 * options object, as well as the value of the <code>fingers</code> event property.
378 * These properties are read only, attempting to change them will not alter the values passed to the event handlers.
381 * @see $.fn.swipe.defaults#fingers
382 * @property {string} ONE Constant indicating 1 finger is to be detected / was detected. Value is <code>1</code>.
383 * @property {string} TWO Constant indicating 2 fingers are to be detected / were detected. Value is <code>2</code>.
384 * @property {string} THREE Constant indicating 3 finger are to be detected / were detected. Value is <code>3</code>.
385 * @property {string} FOUR Constant indicating 4 finger are to be detected / were detected. Not all devices support this. Value is <code>4</code>.
386 * @property {string} FIVE Constant indicating 5 finger are to be detected / were detected. Not all devices support this. Value is <code>5</code>.
387 * @property {string} ALL Constant indicating any combination of finger are to be detected. Value is <code>"all"</code>.
389 $. fn
. swipe
. fingers
= {
399 * Initialise the plugin for each DOM element matched
400 * This creates a new instance of the main TouchSwipe class for each DOM element, and then
401 * saves a reference to that instance in the elements data property.
404 function init ( options
) {
405 //Prep and extend the options
406 if ( options
&& ( options
. allowPageScroll
=== undefined && ( options
. swipe
!== undefined || options
. swipeStatus
!== undefined ))) {
407 options
. allowPageScroll
= NONE
;
410 //Check for deprecated options
411 //Ensure that any old click handlers are assigned to the new tap, unless we have a tap
412 if ( options
. click
!== undefined && options
. tap
=== undefined ) {
413 options
. tap
= options
. click
;
420 //pass empty object so we dont modify the defaults
421 options
= $. extend ({}, $. fn
. swipe
. defaults
, options
);
423 //For each element instantiate the plugin
424 return this . each ( function () {
427 //Check we havent already initialised the plugin
428 var plugin
= $ this . data ( PLUGIN_NS
);
431 plugin
= new TouchSwipe ( this , options
);
432 $ this . data ( PLUGIN_NS
, plugin
);
438 * Main TouchSwipe Plugin Class.
439 * Do not use this to construct your TouchSwipe object, use the jQuery plugin method $.fn.swipe(); {@link $.fn.swipe}
442 * @param {DOMNode} element The HTML DOM object to apply to plugin to
443 * @param {Object} options The options to configure the plugin with. @link {$.fn.swipe.defaults}
444 * @see $.fh.swipe.defaults
448 function TouchSwipe ( element
, options
) {
450 //take a local/instacne level copy of the options - should make it this.options really...
451 var options
= $. extend ({}, options
);
453 var useTouchEvents
= ( SUPPORTS_TOUCH
|| SUPPORTS_POINTER
|| ! options
. fallbackToMouseEvents
),
454 START_EV
= useTouchEvents
? ( SUPPORTS_POINTER
? ( SUPPORTS_POINTER_IE10
? 'MSPointerDown' : 'pointerdown' ) : 'touchstart' ) : 'mousedown' ,
455 MOVE_EV
= useTouchEvents
? ( SUPPORTS_POINTER
? ( SUPPORTS_POINTER_IE10
? 'MSPointerMove' : 'pointermove' ) : 'touchmove' ) : 'mousemove' ,
456 END_EV
= useTouchEvents
? ( SUPPORTS_POINTER
? ( SUPPORTS_POINTER_IE10
? 'MSPointerUp' : 'pointerup' ) : 'touchend' ) : 'mouseup' ,
457 LEAVE_EV
= useTouchEvents
? ( SUPPORTS_POINTER
? 'mouseleave' : null ) : 'mouseleave' , //we manually detect leave on touch devices, so null event here
458 CANCEL_EV
= ( SUPPORTS_POINTER
? ( SUPPORTS_POINTER_IE10
? 'MSPointerCancel' : 'pointercancel' ) : 'touchcancel' );
465 currentDirection
= null ,
467 startTouchesDistance
= 0 ,
468 endTouchesDistance
= 0 ,
476 //jQuery wrapped element for this instance
477 var $ element
= $( element
);
479 //Current phase of th touch cycle
482 // the current number of fingers being used.
485 //track mouse points / delta
491 previousTouchEndTime
= 0 ,
492 fingerCountAtRelease
= 0 ,
493 doubleTapStartTime
= 0 ;
496 var singleTapTimeout
= null ,
499 // Add gestures to all swipable areas if supported
501 $ element
. bind ( START_EV
, touchStart
);
502 $ element
. bind ( CANCEL_EV
, touchCancel
);
504 $. error ( 'events not supported ' + START_EV
+ ',' + CANCEL_EV
+ ' on jQuery.swipe' );
512 * re-enables the swipe plugin with the previous configuration
514 * @name $.fn.swipe#enable
515 * @return {DOMNode} The Dom element that was registered with TouchSwipe
516 * @example $("#element").swipe("enable");
518 this . enable = function () {
519 $ element
. bind ( START_EV
, touchStart
);
520 $ element
. bind ( CANCEL_EV
, touchCancel
);
525 * disables the swipe plugin
527 * @name $.fn.swipe#disable
528 * @return {DOMNode} The Dom element that is now registered with TouchSwipe
529 * @example $("#element").swipe("disable");
531 this . disable = function () {
537 * Destroy the swipe plugin completely. To use any swipe methods, you must re initialise the plugin.
539 * @name $.fn.swipe#destroy
540 * @example $("#element").swipe("destroy");
542 this . destroy = function () {
544 $ element
. data ( PLUGIN_NS
, null );
550 * Allows run time updating of the swipe configuration options.
552 * @name $.fn.swipe#option
553 * @param {String} property The option property to get or set, or a has of multiple options to set
554 * @param {Object} [value] The value to set the property to
555 * @return {Object} If only a property name is passed, then that property value is returned. If nothing is passed the current options hash is returned.
556 * @example $("#element").swipe("option", "threshold"); // return the threshold
557 * @example $("#element").swipe("option", "threshold", 100); // set the threshold after init
558 * @example $("#element").swipe("option", {threshold:100, fingers:3} ); // set multiple properties after init
559 * @example $("#element").swipe({threshold:100, fingers:3} ); // set multiple properties after init - the "option" method is optional!
560 * @example $("#element").swipe("option"); // Return the current options hash
561 * @see $.fn.swipe.defaults
564 this . option = function ( property
, value
) {
566 if ( typeof property
=== 'object' ) {
567 options
= $. extend ( options
, property
);
568 } else if ( options
[ property
] !== undefined ) {
569 if ( value
=== undefined ) {
570 return options
[ property
];
572 options
[ property
] = value
;
574 } else if (! property
) {
577 $. error ( 'Option ' + property
+ ' does not exist on jQuery.swipe.options' );
593 * Event handler for a touch start event.
594 * Stops the default click event from triggering and stores where we touched
596 * @param {object} jqEvent The normalised jQuery event object.
598 function touchStart ( jqEvent
) {
600 //If we already in a touch event (a finger already in use) then ignore subsequent ones..
601 if ( getTouchInProgress ()) {
605 //Check if this element matches any in the excluded elements selectors, or its parent is excluded, if so, DON'T swipe
606 if ($( jqEvent
. target
). closest ( options
. excludedElements
, $ element
). length
> 0 ) {
610 //As we use Jquery bind for events, we need to target the original event object
611 //If these events are being programmatically triggered, we don't have an original event object, so use the Jq one.
612 var event
= jqEvent
. originalEvent
? jqEvent
. originalEvent : jqEvent
;
615 touches
= event
. touches
,
616 evt
= touches
? touches
[ 0 ] : event
;
620 //If we support touches, get the finger count
622 // get the total number of fingers touching the screen
623 fingerCount
= touches
. length
;
625 //Else this is the desktop, so stop the browser from dragging content
626 else if ( options
. preventDefaultEvents
!== false ) {
627 jqEvent
. preventDefault (); //call this on jq event so we are cross browser
633 currentDirection
= null ;
634 pinchDirection
= null ;
636 startTouchesDistance
= 0 ;
637 endTouchesDistance
= 0 ;
640 maximumsMap
= createMaximumsData ();
641 cancelMultiFingerRelease ();
643 //Create the default finger data
644 createFingerData ( 0 , evt
);
646 // check the number of fingers is what we are looking for, or we are capturing pinches
647 if (! touches
|| ( fingerCount
=== options
. fingers
|| options
. fingers
=== ALL_FINGERS
) || hasPinches ()) {
648 // get the coordinates of the touch
649 startTime
= getTimeStamp ();
651 if ( fingerCount
== 2 ) {
652 //Keep track of the initial pinch distance, so we can calculate the diff later
653 //Store second finger data as start
654 createFingerData ( 1 , touches
[ 1 ]);
655 startTouchesDistance
= endTouchesDistance
= calculateTouchesDistance ( fingerData
[ 0 ]. start
, fingerData
[ 1 ]. start
);
658 if ( options
. swipeStatus
|| options
. pinchStatus
) {
659 ret
= triggerHandler ( event
, phase
);
662 //A touch with more or less than the fingers we are looking for, so cancel
666 //If we have a return value from the users handler, then return and cancel
668 phase
= PHASE_CANCEL
;
669 triggerHandler ( event
, phase
);
673 holdTimeout
= setTimeout ($. proxy ( function () {
675 $ element
. trigger ( 'hold' , [ event
. target
]);
678 ret
= options
. hold
. call ($ element
, event
, event
. target
);
680 }, this ), options
. longTapThreshold
);
683 setTouchInProgress ( true );
692 * Event handler for a touch move event.
693 * If we change fingers during move, then cancel the event
695 * @param {object} jqEvent The normalised jQuery event object.
697 function touchMove ( jqEvent
) {
699 //As we use Jquery bind for events, we need to target the original event object
700 //If these events are being programmatically triggered, we don't have an original event object, so use the Jq one.
701 var event
= jqEvent
. originalEvent
? jqEvent
. originalEvent : jqEvent
;
703 //If we are ending, cancelling, or within the threshold of 2 fingers being released, don't track anything..
704 if ( phase
=== PHASE_END
|| phase
=== PHASE_CANCEL
|| inMultiFingerRelease ())
708 touches
= event
. touches
,
709 evt
= touches
? touches
[ 0 ] : event
;
712 //Update the finger data
713 var currentFinger
= updateFingerData ( evt
);
714 endTime
= getTimeStamp ();
717 fingerCount
= touches
. length
;
721 clearTimeout ( holdTimeout
);
725 //If we have 2 fingers get Touches distance as well
726 if ( fingerCount
== 2 ) {
728 //Keep track of the initial pinch distance, so we can calculate the diff later
729 //We do this here as well as the start event, in case they start with 1 finger, and the press 2 fingers
730 if ( startTouchesDistance
== 0 ) {
731 //Create second finger if this is the first time...
732 createFingerData ( 1 , touches
[ 1 ]);
734 startTouchesDistance
= endTouchesDistance
= calculateTouchesDistance ( fingerData
[ 0 ]. start
, fingerData
[ 1 ]. start
);
736 //Else just update the second finger
737 updateFingerData ( touches
[ 1 ]);
739 endTouchesDistance
= calculateTouchesDistance ( fingerData
[ 0 ]. end
, fingerData
[ 1 ]. end
);
740 pinchDirection
= calculatePinchDirection ( fingerData
[ 0 ]. end
, fingerData
[ 1 ]. end
);
743 pinchZoom
= calculatePinchZoom ( startTouchesDistance
, endTouchesDistance
);
744 pinchDistance
= Math
. abs ( startTouchesDistance
- endTouchesDistance
);
747 if (( fingerCount
=== options
. fingers
|| options
. fingers
=== ALL_FINGERS
) || ! touches
|| hasPinches ()) {
749 //The overall direction of the swipe. From start to now.
750 direction
= calculateDirection ( currentFinger
. start
, currentFinger
. end
);
752 //The immediate direction of the swipe, direction between the last movement and this one.
753 currentDirection
= calculateDirection ( currentFinger
. last
, currentFinger
. end
);
755 //Check if we need to prevent default event (page scroll / pinch zoom) or not
756 validateDefaultEvent ( jqEvent
, currentDirection
);
758 //Distance and duration are all off the main finger
759 distance
= calculateDistance ( currentFinger
. start
, currentFinger
. end
);
760 duration
= calculateDuration ();
762 //Cache the maximum distance we made in this direction
763 setMaxDistance ( direction
, distance
);
765 //Trigger status handler
766 ret
= triggerHandler ( event
, phase
);
769 //If we trigger end events when threshold are met, or trigger events when touch leaves element
770 if (! options
. triggerOnTouchEnd
|| options
. triggerOnTouchLeave
) {
774 //If checking if we leave the element, run the bounds check (we can use touchleave as its not supported on webkit)
775 if ( options
. triggerOnTouchLeave
) {
776 var bounds
= getbounds ( this );
777 inBounds
= isInBounds ( currentFinger
. end
, bounds
);
780 //Trigger end handles as we swipe if thresholds met or if we have left the element if the user has asked to check these..
781 if (! options
. triggerOnTouchEnd
&& inBounds
) {
782 phase
= getNextPhase ( PHASE_MOVE
);
784 //We end if out of bounds here, so set current phase to END, and check if its modified
785 else if ( options
. triggerOnTouchLeave
&& ! inBounds
) {
786 phase
= getNextPhase ( PHASE_END
);
789 if ( phase
== PHASE_CANCEL
|| phase
== PHASE_END
) {
790 triggerHandler ( event
, phase
);
794 phase
= PHASE_CANCEL
;
795 triggerHandler ( event
, phase
);
799 phase
= PHASE_CANCEL
;
800 triggerHandler ( event
, phase
);
808 * Event handler for a touch end event.
809 * Calculate the direction and trigger events
811 * @param {object} jqEvent The normalised jQuery event object.
813 function touchEnd ( jqEvent
) {
814 //As we use Jquery bind for events, we need to target the original event object
815 //If these events are being programmatically triggered, we don't have an original event object, so use the Jq one.
816 var event
= jqEvent
. originalEvent
? jqEvent
. originalEvent : jqEvent
,
817 touches
= event
. touches
;
819 //If we are still in a touch with the device wait a fraction and see if the other finger comes up
820 //if it does within the threshold, then we treat it as a multi release, not a single release and end the touch / swipe
822 if ( touches
. length
&& ! inMultiFingerRelease ()) {
823 startMultiFingerRelease ( event
);
825 } else if ( touches
. length
&& inMultiFingerRelease ()) {
830 //If a previous finger has been released, check how long ago, if within the threshold, then assume it was a multifinger release.
831 //This is used to allow 2 fingers to release fractionally after each other, whilst maintaining the event as containing 2 fingers, not 1
832 if ( inMultiFingerRelease ()) {
833 fingerCount
= fingerCountAtRelease
;
837 endTime
= getTimeStamp ();
839 //Get duration incase move was never fired
840 duration
= calculateDuration ();
842 //If we trigger handlers at end of swipe OR, we trigger during, but they didnt trigger and we are still in the move phase
843 if ( didSwipeBackToCancel () || ! validateSwipeDistance ()) {
844 phase
= PHASE_CANCEL
;
845 triggerHandler ( event
, phase
);
846 } else if ( options
. triggerOnTouchEnd
|| ( options
. triggerOnTouchEnd
== false && phase
=== PHASE_MOVE
)) {
847 //call this on jq event so we are cross browser
848 if ( options
. preventDefaultEvents
!== false ) {
849 jqEvent
. preventDefault ();
852 triggerHandler ( event
, phase
);
854 //Special cases - A tap should always fire on touch end regardless,
855 //So here we manually trigger the tap end handler by itself
856 //We dont run trigger handler as it will re-trigger events that may have fired already
857 else if (! options
. triggerOnTouchEnd
&& hasTap ()) {
858 //Trigger the pinch events...
860 triggerHandlerForGesture ( event
, phase
, TAP
);
861 } else if ( phase
=== PHASE_MOVE
) {
862 phase
= PHASE_CANCEL
;
863 triggerHandler ( event
, phase
);
866 setTouchInProgress ( false );
874 * Event handler for a touch cancel event.
875 * Clears current vars
878 function touchCancel () {
879 // reset the variables back to default values
883 startTouchesDistance
= 0 ;
884 endTouchesDistance
= 0 ;
887 //If we were in progress of tracking a possible multi touch end, then re set it.
888 cancelMultiFingerRelease ();
890 setTouchInProgress ( false );
895 * Event handler for a touch leave event.
896 * This is only triggered on desktops, in touch we work this out manually
897 * as the touchleave event is not supported in webkit
900 function touchLeave ( jqEvent
) {
901 //If these events are being programmatically triggered, we don't have an original event object, so use the Jq one.
902 var event
= jqEvent
. originalEvent
? jqEvent
. originalEvent : jqEvent
;
904 //If we have the trigger on leave property set....
905 if ( options
. triggerOnTouchLeave
) {
906 phase
= getNextPhase ( PHASE_END
);
907 triggerHandler ( event
, phase
);
912 * Removes all listeners that were associated with the plugin
915 function removeListeners () {
916 $ element
. unbind ( START_EV
, touchStart
);
917 $ element
. unbind ( CANCEL_EV
, touchCancel
);
918 $ element
. unbind ( MOVE_EV
, touchMove
);
919 $ element
. unbind ( END_EV
, touchEnd
);
921 //we only have leave events on desktop, we manually calculate leave on touch as its not supported in webkit
923 $ element
. unbind ( LEAVE_EV
, touchLeave
);
926 setTouchInProgress ( false );
931 * Checks if the time and distance thresholds have been met, and if so then the appropriate handlers are fired.
933 function getNextPhase ( currentPhase
) {
935 var nextPhase
= currentPhase
;
937 // Ensure we have valid swipe (under time and over distance and check if we are out of bound...)
938 var validTime
= validateSwipeTime ();
939 var validDistance
= validateSwipeDistance ();
940 var didCancel
= didSwipeBackToCancel ();
942 //If we have exceeded our time, then cancel
943 if (! validTime
|| didCancel
) {
944 nextPhase
= PHASE_CANCEL
;
946 //Else if we are moving, and have reached distance then end
947 else if ( validDistance
&& currentPhase
== PHASE_MOVE
&& (! options
. triggerOnTouchEnd
|| options
. triggerOnTouchLeave
)) {
948 nextPhase
= PHASE_END
;
950 //Else if we have ended by leaving and didn't reach distance, then cancel
951 else if (! validDistance
&& currentPhase
== PHASE_END
&& options
. triggerOnTouchLeave
) {
952 nextPhase
= PHASE_CANCEL
;
960 * Trigger the relevant event handler
961 * 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"
962 * @param {object} event the original event object
963 * @param {string} phase the phase of the swipe (start, end cancel etc) {@link $.fn.swipe.phases}
966 function triggerHandler ( event
, phase
) {
971 touches
= event
. touches
;
974 if ( didSwipe () || hasSwipes ()) {
975 ret
= triggerHandlerForGesture ( event
, phase
, SWIPE
);
978 // PINCH GESTURES (if the above didn't cancel)
979 if (( didPinch () || hasPinches ()) && ret
!== false ) {
980 ret
= triggerHandlerForGesture ( event
, phase
, PINCH
);
983 // CLICK / TAP (if the above didn't cancel)
984 if ( didDoubleTap () && ret
!== false ) {
985 //Trigger the tap events...
986 ret
= triggerHandlerForGesture ( event
, phase
, DOUBLE_TAP
);
989 // CLICK / TAP (if the above didn't cancel)
990 else if ( didLongTap () && ret
!== false ) {
991 //Trigger the tap events...
992 ret
= triggerHandlerForGesture ( event
, phase
, LONG_TAP
);
995 // CLICK / TAP (if the above didn't cancel)
996 else if ( didTap () && ret
!== false ) {
997 //Trigger the tap event..
998 ret
= triggerHandlerForGesture ( event
, phase
, TAP
);
1001 // If we are cancelling the gesture, then manually trigger the reset handler
1002 if ( phase
=== PHASE_CANCEL
) {
1004 ret
= triggerHandlerForGesture ( event
, phase
, SWIPE
);
1008 ret
= triggerHandlerForGesture ( event
, phase
, PINCH
);
1013 // If we are ending the gesture, then manually trigger the reset handler IF all fingers are off
1014 if ( phase
=== PHASE_END
) {
1015 //If we support touch, then check that all fingers are off before we cancel
1017 if (! touches
. length
) {
1031 * Trigger the relevant event handler
1032 * 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"
1033 * @param {object} event the original event object
1034 * @param {string} phase the phase of the swipe (start, end cancel etc) {@link $.fn.swipe.phases}
1035 * @param {string} gesture the gesture to trigger a handler for : PINCH or SWIPE {@link $.fn.swipe.gestures}
1036 * @return Boolean False, to indicate that the event should stop propagation, or void.
1039 function triggerHandlerForGesture ( event
, phase
, gesture
) {
1044 if ( gesture
== SWIPE
) {
1045 //Trigger status every time..
1046 $ element
. trigger ( 'swipeStatus' , [ phase
, direction
|| null , distance
|| 0 , duration
|| 0 , fingerCount
, fingerData
, currentDirection
]);
1048 if ( options
. swipeStatus
) {
1049 ret
= options
. swipeStatus
. call ($ element
, event
, phase
, direction
|| null , distance
|| 0 , duration
|| 0 , fingerCount
, fingerData
, currentDirection
);
1050 //If the status cancels, then dont run the subsequent event handlers..
1051 if ( ret
=== false ) return false ;
1054 if ( phase
== PHASE_END
&& validateSwipe ()) {
1056 //Cancel any taps that were in progress...
1057 clearTimeout ( singleTapTimeout
);
1058 clearTimeout ( holdTimeout
);
1060 $ element
. trigger ( 'swipe' , [ direction
, distance
, duration
, fingerCount
, fingerData
, currentDirection
]);
1062 if ( options
. swipe
) {
1063 ret
= options
. swipe
. call ($ element
, event
, direction
, distance
, duration
, fingerCount
, fingerData
, currentDirection
);
1064 //If the status cancels, then dont run the subsequent event handlers..
1065 if ( ret
=== false ) return false ;
1068 //trigger direction specific event handlers
1069 switch ( direction
) {
1071 $ element
. trigger ( 'swipeLeft' , [ direction
, distance
, duration
, fingerCount
, fingerData
, currentDirection
]);
1073 if ( options
. swipeLeft
) {
1074 ret
= options
. swipeLeft
. call ($ element
, event
, direction
, distance
, duration
, fingerCount
, fingerData
, currentDirection
);
1079 $ element
. trigger ( 'swipeRight' , [ direction
, distance
, duration
, fingerCount
, fingerData
, currentDirection
]);
1081 if ( options
. swipeRight
) {
1082 ret
= options
. swipeRight
. call ($ element
, event
, direction
, distance
, duration
, fingerCount
, fingerData
, currentDirection
);
1087 $ element
. trigger ( 'swipeUp' , [ direction
, distance
, duration
, fingerCount
, fingerData
, currentDirection
]);
1089 if ( options
. swipeUp
) {
1090 ret
= options
. swipeUp
. call ($ element
, event
, direction
, distance
, duration
, fingerCount
, fingerData
, currentDirection
);
1095 $ element
. trigger ( 'swipeDown' , [ direction
, distance
, duration
, fingerCount
, fingerData
, currentDirection
]);
1097 if ( options
. swipeDown
) {
1098 ret
= options
. swipeDown
. call ($ element
, event
, direction
, distance
, duration
, fingerCount
, fingerData
, currentDirection
);
1107 if ( gesture
== PINCH
) {
1108 $ element
. trigger ( 'pinchStatus' , [ phase
, pinchDirection
|| null , pinchDistance
|| 0 , duration
|| 0 , fingerCount
, pinchZoom
, fingerData
]);
1110 if ( options
. pinchStatus
) {
1111 ret
= options
. pinchStatus
. call ($ element
, event
, phase
, pinchDirection
|| null , pinchDistance
|| 0 , duration
|| 0 , fingerCount
, pinchZoom
, fingerData
);
1112 //If the status cancels, then dont run the subsequent event handlers..
1113 if ( ret
=== false ) return false ;
1116 if ( phase
== PHASE_END
&& validatePinch ()) {
1118 switch ( pinchDirection
) {
1120 $ element
. trigger ( 'pinchIn' , [ pinchDirection
|| null , pinchDistance
|| 0 , duration
|| 0 , fingerCount
, pinchZoom
, fingerData
]);
1122 if ( options
. pinchIn
) {
1123 ret
= options
. pinchIn
. call ($ element
, event
, pinchDirection
|| null , pinchDistance
|| 0 , duration
|| 0 , fingerCount
, pinchZoom
, fingerData
);
1128 $ element
. trigger ( 'pinchOut' , [ pinchDirection
|| null , pinchDistance
|| 0 , duration
|| 0 , fingerCount
, pinchZoom
, fingerData
]);
1130 if ( options
. pinchOut
) {
1131 ret
= options
. pinchOut
. call ($ element
, event
, pinchDirection
|| null , pinchDistance
|| 0 , duration
|| 0 , fingerCount
, pinchZoom
, fingerData
);
1138 if ( gesture
== TAP
) {
1139 if ( phase
=== PHASE_CANCEL
|| phase
=== PHASE_END
) {
1141 clearTimeout ( singleTapTimeout
);
1142 clearTimeout ( holdTimeout
);
1144 //If we are also looking for doubelTaps, wait incase this is one...
1145 if ( hasDoubleTap () && ! inDoubleTap ()) {
1146 doubleTapStartTime
= getTimeStamp ();
1148 //Now wait for the double tap timeout, and trigger this single tap
1149 //if its not cancelled by a double tap
1150 singleTapTimeout
= setTimeout ($. proxy ( function () {
1151 doubleTapStartTime
= null ;
1152 $ element
. trigger ( 'tap' , [ event
. target
]);
1155 ret
= options
. tap
. call ($ element
, event
, event
. target
);
1157 }, this ), options
. doubleTapThreshold
);
1160 doubleTapStartTime
= null ;
1161 $ element
. trigger ( 'tap' , [ event
. target
]);
1163 ret
= options
. tap
. call ($ element
, event
, event
. target
);
1167 } else if ( gesture
== DOUBLE_TAP
) {
1168 if ( phase
=== PHASE_CANCEL
|| phase
=== PHASE_END
) {
1169 clearTimeout ( singleTapTimeout
);
1170 clearTimeout ( holdTimeout
);
1171 doubleTapStartTime
= null ;
1172 $ element
. trigger ( 'doubletap' , [ event
. target
]);
1174 if ( options
. doubleTap
) {
1175 ret
= options
. doubleTap
. call ($ element
, event
, event
. target
);
1178 } else if ( gesture
== LONG_TAP
) {
1179 if ( phase
=== PHASE_CANCEL
|| phase
=== PHASE_END
) {
1180 clearTimeout ( singleTapTimeout
);
1181 doubleTapStartTime
= null ;
1183 $ element
. trigger ( 'longtap' , [ event
. target
]);
1184 if ( options
. longTap
) {
1185 ret
= options
. longTap
. call ($ element
, event
, event
. target
);
1195 // GESTURE VALIDATION
1199 * Checks the user has swipe far enough
1200 * @return Boolean if <code>threshold</code> has been set, return true if the threshold was met, else false.
1201 * If no threshold was set, then we return true.
1204 function validateSwipeDistance () {
1206 //If we made it past the min swipe distance..
1207 if ( options
. threshold
!== null ) {
1208 valid
= distance
>= options
. threshold
;
1215 * Checks the user has swiped back to cancel.
1216 * @return Boolean if <code>cancelThreshold</code> has been set, return true if the cancelThreshold was met, else false.
1217 * If no cancelThreshold was set, then we return true.
1220 function didSwipeBackToCancel () {
1221 var cancelled
= false ;
1222 if ( options
. cancelThreshold
!== null && direction
!== null ) {
1223 cancelled
= ( getMaxDistance ( direction
) - distance
) >= options
. cancelThreshold
;
1230 * Checks the user has pinched far enough
1231 * @return Boolean if <code>pinchThreshold</code> has been set, return true if the threshold was met, else false.
1232 * If no threshold was set, then we return true.
1235 function validatePinchDistance () {
1236 if ( options
. pinchThreshold
!== null ) {
1237 return pinchDistance
>= options
. pinchThreshold
;
1243 * Checks that the time taken to swipe meets the minimum / maximum requirements
1247 function validateSwipeTime () {
1249 //If no time set, then return true
1250 if ( options
. maxTimeThreshold
) {
1251 if ( duration
>= options
. maxTimeThreshold
) {
1266 * Checks direction of the swipe and the value allowPageScroll to see if we should allow or prevent the default behaviour from occurring.
1267 * This will essentially allow page scrolling or not when the user is swiping on a touchSwipe object.
1268 * @param {object} jqEvent The normalised jQuery representation of the event object.
1269 * @param {string} direction The direction of the event. See {@link $.fn.swipe.directions}
1270 * @see $.fn.swipe.directions
1273 function validateDefaultEvent ( jqEvent
, direction
) {
1275 //If the option is set, allways allow the event to bubble up (let user handle weirdness)
1276 if ( options
. preventDefaultEvents
=== false ) {
1280 if ( options
. allowPageScroll
=== NONE
) {
1281 jqEvent
. preventDefault ();
1283 var auto
= options
. allowPageScroll
=== AUTO
;
1285 switch ( direction
) {
1287 if (( options
. swipeLeft
&& auto
) || (! auto
&& options
. allowPageScroll
!= HORIZONTAL
)) {
1288 jqEvent
. preventDefault ();
1293 if (( options
. swipeRight
&& auto
) || (! auto
&& options
. allowPageScroll
!= HORIZONTAL
)) {
1294 jqEvent
. preventDefault ();
1299 if (( options
. swipeUp
&& auto
) || (! auto
&& options
. allowPageScroll
!= VERTICAL
)) {
1300 jqEvent
. preventDefault ();
1305 if (( options
. swipeDown
&& auto
) || (! auto
&& options
. allowPageScroll
!= VERTICAL
)) {
1306 jqEvent
. preventDefault ();
1317 * Returns true of the current pinch meets the thresholds
1321 function validatePinch () {
1322 var hasCorrectFingerCount
= validateFingers ();
1323 var hasEndPoint
= validateEndPoint ();
1324 var hasCorrectDistance
= validatePinchDistance ();
1325 return hasCorrectFingerCount
&& hasEndPoint
&& hasCorrectDistance
;
1330 * Returns true if any Pinch events have been registered
1334 function hasPinches () {
1335 //Enure we dont return 0 or null for false values
1336 return !!( options
. pinchStatus
|| options
. pinchIn
|| options
. pinchOut
);
1340 * Returns true if we are detecting pinches, and have one
1344 function didPinch () {
1345 //Enure we dont return 0 or null for false values
1346 return !!( validatePinch () && hasPinches ());
1354 * Returns true if the current swipe meets the thresholds
1358 function validateSwipe () {
1359 //Check validity of swipe
1360 var hasValidTime
= validateSwipeTime ();
1361 var hasValidDistance
= validateSwipeDistance ();
1362 var hasCorrectFingerCount
= validateFingers ();
1363 var hasEndPoint
= validateEndPoint ();
1364 var didCancel
= didSwipeBackToCancel ();
1366 // if the user swiped more than the minimum length, perform the appropriate action
1367 // hasValidDistance is null when no distance is set
1368 var valid
= ! didCancel
&& hasEndPoint
&& hasCorrectFingerCount
&& hasValidDistance
&& hasValidTime
;
1374 * Returns true if any Swipe events have been registered
1378 function hasSwipes () {
1379 //Enure we dont return 0 or null for false values
1380 return !!( options
. swipe
|| options
. swipeStatus
|| options
. swipeLeft
|| options
. swipeRight
|| options
. swipeUp
|| options
. swipeDown
);
1385 * Returns true if we are detecting swipes and have one
1389 function didSwipe () {
1390 //Enure we dont return 0 or null for false values
1391 return !!( validateSwipe () && hasSwipes ());
1395 * Returns true if we have matched the number of fingers we are looking for
1399 function validateFingers () {
1400 //The number of fingers we want were matched, or on desktop we ignore
1401 return (( fingerCount
=== options
. fingers
|| options
. fingers
=== ALL_FINGERS
) || ! SUPPORTS_TOUCH
);
1405 * Returns true if we have an end point for the swipe
1409 function validateEndPoint () {
1410 //We have an end value for the finger
1411 return fingerData
[ 0 ]. end
. x
!== 0 ;
1416 * Returns true if a click / tap events have been registered
1421 //Enure we dont return 0 or null for false values
1422 return !!( options
. tap
);
1426 * Returns true if a double tap events have been registered
1430 function hasDoubleTap () {
1431 //Enure we dont return 0 or null for false values
1432 return !!( options
. doubleTap
);
1436 * Returns true if any long tap events have been registered
1440 function hasLongTap () {
1441 //Enure we dont return 0 or null for false values
1442 return !!( options
. longTap
);
1446 * 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.
1450 function validateDoubleTap () {
1451 if ( doubleTapStartTime
== null ) {
1454 var now
= getTimeStamp ();
1455 return ( hasDoubleTap () && (( now
- doubleTapStartTime
) <= options
. doubleTapThreshold
));
1459 * 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.
1463 function inDoubleTap () {
1464 return validateDoubleTap ();
1469 * Returns true if we have a valid tap
1473 function validateTap () {
1474 return (( fingerCount
=== 1 || ! SUPPORTS_TOUCH
) && ( isNaN ( distance
) || distance
< options
. threshold
));
1478 * Returns true if we have a valid long tap
1482 function validateLongTap () {
1483 //slight threshold on moving finger
1484 return (( duration
> options
. longTapThreshold
) && ( distance
< DOUBLE_TAP_THRESHOLD
));
1488 * Returns true if we are detecting taps and have one
1493 //Enure we dont return 0 or null for false values
1494 return !!( validateTap () && hasTap ());
1499 * Returns true if we are detecting double taps and have one
1503 function didDoubleTap () {
1504 //Enure we dont return 0 or null for false values
1505 return !!( validateDoubleTap () && hasDoubleTap ());
1509 * Returns true if we are detecting long taps and have one
1513 function didLongTap () {
1514 //Enure we dont return 0 or null for false values
1515 return !!( validateLongTap () && hasLongTap ());
1521 // MULTI FINGER TOUCH
1523 * Starts tracking the time between 2 finger releases, and keeps track of how many fingers we initially had up
1526 function startMultiFingerRelease ( event
) {
1527 previousTouchEndTime
= getTimeStamp ();
1528 fingerCountAtRelease
= event
. touches
. length
+ 1 ;
1532 * Cancels the tracking of time between 2 finger releases, and resets counters
1535 function cancelMultiFingerRelease () {
1536 previousTouchEndTime
= 0 ;
1537 fingerCountAtRelease
= 0 ;
1541 * Checks if we are in the threshold between 2 fingers being released
1545 function inMultiFingerRelease () {
1547 var withinThreshold
= false ;
1549 if ( previousTouchEndTime
) {
1550 var diff
= getTimeStamp () - previousTouchEndTime
1551 if ( diff
<= options
. fingerReleaseThreshold
) {
1552 withinThreshold
= true ;
1556 return withinThreshold
;
1561 * gets a data flag to indicate that a touch is in progress
1565 function getTouchInProgress () {
1566 //strict equality to ensure only true and false are returned
1567 return !!($ element
. data ( PLUGIN_NS
+ '_intouch' ) === true );
1571 * Sets a data flag to indicate that a touch is in progress
1572 * @param {boolean} val The value to set the property to
1575 function setTouchInProgress ( val
) {
1577 //If destroy is called in an event handler, we have no el, and we have already cleaned up, so return.
1578 if (!$ element
) { return ; }
1580 //Add or remove event listeners depending on touch status
1582 $ element
. bind ( MOVE_EV
, touchMove
);
1583 $ element
. bind ( END_EV
, touchEnd
);
1585 //we only have leave events on desktop, we manually calcuate leave on touch as its not supported in webkit
1587 $ element
. bind ( LEAVE_EV
, touchLeave
);
1591 $ element
. unbind ( MOVE_EV
, touchMove
, false );
1592 $ element
. unbind ( END_EV
, touchEnd
, false );
1594 //we only have leave events on desktop, we manually calcuate leave on touch as its not supported in webkit
1596 $ element
. unbind ( LEAVE_EV
, touchLeave
, false );
1601 //strict equality to ensure only true and false can update the value
1602 $ element
. data ( PLUGIN_NS
+ '_intouch' , val
=== true );
1607 * Creates the finger data for the touch/finger in the event object.
1608 * @param {int} id The id to store the finger data under (usually the order the fingers were pressed)
1609 * @param {object} evt The event object containing finger data
1610 * @return finger data object
1613 function createFingerData ( id
, evt
) {
1628 f
. start
. x
= f
. last
. x
= f
. end
. x
= evt
. pageX
|| evt
. clientX
;
1629 f
. start
. y
= f
. last
. y
= f
. end
. y
= evt
. pageY
|| evt
. clientY
;
1635 * Updates the finger data for a particular event object
1636 * @param {object} evt The event object containing the touch/finger data to upadte
1637 * @return a finger data object.
1640 function updateFingerData ( evt
) {
1641 var id
= evt
. identifier
!== undefined ? evt
. identifier : 0 ;
1642 var f
= getFingerData ( id
);
1645 f
= createFingerData ( id
, evt
);
1651 f
. end
. x
= evt
. pageX
|| evt
. clientX
;
1652 f
. end
. y
= evt
. pageY
|| evt
. clientY
;
1658 * Returns a finger data object by its event ID.
1659 * Each touch event has an identifier property, which is used
1660 * to track repeat touches
1661 * @param {int} id The unique id of the finger in the sequence of touch events.
1662 * @return a finger data object.
1665 function getFingerData ( id
) {
1666 return fingerData
[ id
] || null ;
1671 * Sets the maximum distance swiped in the given direction.
1672 * If the new value is lower than the current value, the max value is not changed.
1673 * @param {string} direction The direction of the swipe
1674 * @param {int} distance The distance of the swipe
1677 function setMaxDistance ( direction
, distance
) {
1678 distance
= Math
. max ( distance
, getMaxDistance ( direction
));
1679 maximumsMap
[ direction
]. distance
= distance
;
1683 * gets the maximum distance swiped in the given direction.
1684 * @param {string} direction The direction of the swipe
1685 * @return int The distance of the swipe
1688 function getMaxDistance ( direction
) {
1689 if ( maximumsMap
[ direction
]) return maximumsMap
[ direction
]. distance
;
1694 * Creats a map of directions to maximum swiped values.
1695 * @return Object A dictionary of maximum values, indexed by direction.
1698 function createMaximumsData () {
1700 maxData
[ LEFT
] = createMaximumVO ( LEFT
);
1701 maxData
[ RIGHT
] = createMaximumVO ( RIGHT
);
1702 maxData
[ UP
] = createMaximumVO ( UP
);
1703 maxData
[ DOWN
] = createMaximumVO ( DOWN
);
1709 * Creates a map maximum swiped values for a given swipe direction
1710 * @param {string} The direction that these values will be associated with
1711 * @return Object Maximum values
1714 function createMaximumVO ( dir
) {
1727 * Calculate the duration of the swipe
1731 function calculateDuration () {
1732 return endTime
- startTime
;
1736 * Calculate the distance between 2 touches (pinch)
1737 * @param {point} startPoint A point object containing x and y co-ordinates
1738 * @param {point} endPoint A point object containing x and y co-ordinates
1742 function calculateTouchesDistance ( startPoint
, endPoint
) {
1743 var diffX
= Math
. abs ( startPoint
. x
- endPoint
. x
);
1744 var diffY
= Math
. abs ( startPoint
. y
- endPoint
. y
);
1746 return Math
. round ( Math
. sqrt ( diffX
* diffX
+ diffY
* diffY
));
1750 * Calculate the zoom factor between the start and end distances
1751 * @param {int} startDistance Distance (between 2 fingers) the user started pinching at
1752 * @param {int} endDistance Distance (between 2 fingers) the user ended pinching at
1753 * @return float The zoom value from 0 to 1.
1756 function calculatePinchZoom ( startDistance
, endDistance
) {
1757 var percent
= ( endDistance
/ startDistance
) * 1 ;
1758 return percent
. toFixed ( 2 );
1763 * Returns the pinch direction, either IN or OUT for the given points
1764 * @return string Either {@link $.fn.swipe.directions.IN} or {@link $.fn.swipe.directions.OUT}
1765 * @see $.fn.swipe.directions
1768 function calculatePinchDirection () {
1769 if ( pinchZoom
< 1 ) {
1778 * Calculate the length / distance of the swipe
1779 * @param {point} startPoint A point object containing x and y co-ordinates
1780 * @param {point} endPoint A point object containing x and y co-ordinates
1784 function calculateDistance ( startPoint
, endPoint
) {
1785 return Math
. round ( Math
. sqrt ( Math
. pow ( endPoint
. x
- startPoint
. x
, 2 ) + Math
. pow ( endPoint
. y
- startPoint
. y
, 2 )));
1789 * Calculate the angle of the swipe
1790 * @param {point} startPoint A point object containing x and y co-ordinates
1791 * @param {point} endPoint A point object containing x and y co-ordinates
1795 function calculateAngle ( startPoint
, endPoint
) {
1796 var x
= startPoint
. x
- endPoint
. x
;
1797 var y
= endPoint
. y
- startPoint
. y
;
1798 var r
= Math
. atan2 ( y
, x
); //radians
1799 var angle
= Math
. round ( r
* 180 / Math
. PI
); //degrees
1801 //ensure value is positive
1803 angle
= 360 - Math
. abs ( angle
);
1810 * Calculate the direction of the swipe
1811 * This will also call calculateAngle to get the latest angle of swipe
1812 * @param {point} startPoint A point object containing x and y co-ordinates
1813 * @param {point} endPoint A point object containing x and y co-ordinates
1814 * @return string Either {@link $.fn.swipe.directions.LEFT} / {@link $.fn.swipe.directions.RIGHT} / {@link $.fn.swipe.directions.DOWN} / {@link $.fn.swipe.directions.UP}
1815 * @see $.fn.swipe.directions
1818 function calculateDirection ( startPoint
, endPoint
) {
1819 var angle
= calculateAngle ( startPoint
, endPoint
);
1821 if (( angle
<= 45 ) && ( angle
>= 0 )) {
1823 } else if (( angle
<= 360 ) && ( angle
>= 315 )) {
1825 } else if (( angle
>= 135 ) && ( angle
<= 225 )) {
1827 } else if (( angle
> 45 ) && ( angle
< 135 )) {
1836 * Returns a MS time stamp of the current time
1840 function getTimeStamp () {
1841 var now
= new Date ();
1842 return now
. getTime ();
1848 * Returns a bounds object with left, right, top and bottom properties for the element specified.
1849 * @param {DomNode} The DOM node to get the bounds for.
1851 function getbounds ( el
) {
1853 var offset
= el
. offset ();
1857 right : offset
. left
+ el
. outerWidth (),
1859 bottom : offset
. top
+ el
. outerHeight ()
1867 * Checks if the point object is in the bounds object.
1868 * @param {object} point A point object.
1869 * @param {int} point.x The x value of the point.
1870 * @param {int} point.y The x value of the point.
1871 * @param {object} bounds The bounds object to test
1872 * @param {int} bounds.left The leftmost value
1873 * @param {int} bounds.right The righttmost value
1874 * @param {int} bounds.top The topmost value
1875 * @param {int} bounds.bottom The bottommost value
1877 function isInBounds ( point
, bounds
) {
1878 return ( point
. x
> bounds
. left
&& point
. x
< bounds
. right
&& point
. y
> bounds
. top
&& point
. y
< bounds
. bottom
);
1888 * A catch all handler that is triggered for all swipe directions.
1889 * @name $.fn.swipe#swipe
1892 * @param {EventObject} event The original event object
1893 * @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
1894 * @param {int} distance The distance the user swiped
1895 * @param {int} duration The duration of the swipe in milliseconds
1896 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1897 * @param {object} fingerData The coordinates of fingers in event
1898 * @param {string} currentDirection The current direction the user is swiping.
1905 * A handler that is triggered for "left" swipes.
1906 * @name $.fn.swipe#swipeLeft
1909 * @param {EventObject} event The original event object
1910 * @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
1911 * @param {int} distance The distance the user swiped
1912 * @param {int} duration The duration of the swipe in milliseconds
1913 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1914 * @param {object} fingerData The coordinates of fingers in event
1915 * @param {string} currentDirection The current direction the user is swiping.
1919 * A handler that is triggered for "right" swipes.
1920 * @name $.fn.swipe#swipeRight
1923 * @param {EventObject} event The original event object
1924 * @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
1925 * @param {int} distance The distance the user swiped
1926 * @param {int} duration The duration of the swipe in milliseconds
1927 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1928 * @param {object} fingerData The coordinates of fingers in event
1929 * @param {string} currentDirection The current direction the user is swiping.
1933 * A handler that is triggered for "up" swipes.
1934 * @name $.fn.swipe#swipeUp
1937 * @param {EventObject} event The original event object
1938 * @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
1939 * @param {int} distance The distance the user swiped
1940 * @param {int} duration The duration of the swipe in milliseconds
1941 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1942 * @param {object} fingerData The coordinates of fingers in event
1943 * @param {string} currentDirection The current direction the user is swiping.
1947 * A handler that is triggered for "down" swipes.
1948 * @name $.fn.swipe#swipeDown
1951 * @param {EventObject} event The original event object
1952 * @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
1953 * @param {int} distance The distance the user swiped
1954 * @param {int} duration The duration of the swipe in milliseconds
1955 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1956 * @param {object} fingerData The coordinates of fingers in event
1957 * @param {string} currentDirection The current direction the user is swiping.
1961 * A handler triggered for every phase of the swipe. This handler is constantly fired for the duration of the pinch.
1962 * This is triggered regardless of swipe thresholds.
1963 * @name $.fn.swipe#swipeStatus
1966 * @param {EventObject} event The original event object
1967 * @param {string} phase The phase of the swipe event. See {@link $.fn.swipe.phases}
1968 * @param {string} direction The direction the user swiped in. This is null if the user has yet to move. See {@link $.fn.swipe.directions}
1969 * @param {int} distance The distance the user swiped. This is 0 if the user has yet to move.
1970 * @param {int} duration The duration of the swipe in milliseconds
1971 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1972 * @param {object} fingerData The coordinates of fingers in event
1973 * @param {string} currentDirection The current direction the user is swiping.
1977 * A handler triggered for pinch in events.
1978 * @name $.fn.swipe#pinchIn
1981 * @param {EventObject} event The original event object
1982 * @param {int} direction The direction the user pinched in. See {@link $.fn.swipe.directions}
1983 * @param {int} distance The distance the user pinched
1984 * @param {int} duration The duration of the swipe in milliseconds
1985 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1986 * @param {int} zoom The zoom/scale level the user pinched too, 0-1.
1987 * @param {object} fingerData The coordinates of fingers in event
1991 * A handler triggered for pinch out events.
1992 * @name $.fn.swipe#pinchOut
1995 * @param {EventObject} event The original event object
1996 * @param {int} direction The direction the user pinched in. See {@link $.fn.swipe.directions}
1997 * @param {int} distance The distance the user pinched
1998 * @param {int} duration The duration of the swipe in milliseconds
1999 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
2000 * @param {int} zoom The zoom/scale level the user pinched too, 0-1.
2001 * @param {object} fingerData The coordinates of fingers in event
2005 * A handler triggered for all pinch events. This handler is constantly fired for the duration of the pinch. This is triggered regardless of thresholds.
2006 * @name $.fn.swipe#pinchStatus
2009 * @param {EventObject} event The original event object
2010 * @param {int} direction The direction the user pinched in. See {@link $.fn.swipe.directions}
2011 * @param {int} distance The distance the user pinched
2012 * @param {int} duration The duration of the swipe in milliseconds
2013 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
2014 * @param {int} zoom The zoom/scale level the user pinched too, 0-1.
2015 * @param {object} fingerData The coordinates of fingers in event
2019 * A click handler triggered when a user simply clicks, rather than swipes on an element.
2020 * This is deprecated since version 1.6.2, any assignment to click will be assigned to the tap handler.
2021 * You cannot use <code>on</code> to bind to this event as the default jQ <code>click</code> event will be triggered.
2022 * Use the <code>tap</code> event instead.
2023 * @name $.fn.swipe#click
2025 * @deprecated since version 1.6.2, please use {@link $.fn.swipe#tap} instead
2027 * @param {EventObject} event The original event object
2028 * @param {DomObject} target The element clicked on.
2032 * A click / tap handler triggered when a user simply clicks or taps, rather than swipes on an element.
2033 * @name $.fn.swipe#tap
2036 * @param {EventObject} event The original event object
2037 * @param {DomObject} target The element clicked on.
2041 * A double tap handler triggered when a user double clicks or taps on an element.
2042 * You can set the time delay for a double tap with the {@link $.fn.swipe.defaults#doubleTapThreshold} property.
2043 * 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>
2044 * as the script needs to check if its a double tap.
2045 * @name $.fn.swipe#doubleTap
2046 * @see $.fn.swipe.defaults#doubleTapThreshold
2049 * @param {EventObject} event The original event object
2050 * @param {DomObject} target The element clicked on.
2054 * A long tap handler triggered once a tap has been release if the tap was longer than the longTapThreshold.
2055 * You can set the time delay for a long tap with the {@link $.fn.swipe.defaults#longTapThreshold} property.
2056 * @name $.fn.swipe#longTap
2057 * @see $.fn.swipe.defaults#longTapThreshold
2060 * @param {EventObject} event The original event object
2061 * @param {DomObject} target The element clicked on.
2065 * A hold tap handler triggered as soon as the longTapThreshold is reached
2066 * You can set the time delay for a long tap with the {@link $.fn.swipe.defaults#longTapThreshold} property.
2067 * @name $.fn.swipe#hold
2068 * @see $.fn.swipe.defaults#longTapThreshold
2071 * @param {EventObject} event The original event object
2072 * @param {DomObject} target The element clicked on.