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