PageSourceSearch

https://www.fieldsbmwnorthfield.com/v9/media/js/jquerytouchswipe/v1.6/jquery.touchSwipe.js

js fieldsbmwnorthfield.com collected 2026-09-28 08:32:23 UTC 78,276 bytes, 2,109 lines download raw bytes

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

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.