PageSourceSearch

https://pasrc.org/resources/js/vendor/15-touchswipe.js?v=1592258561

js pasrc.org collected 2026-10-06 02:17:43 UTC 25,833 bytes, 877 lines download raw bytes

vendor: 25,833 bytes, lines 1-877
1/*
2 * @fileOverview TouchSwipe - jQuery Plugin
3 * @version 1.6.9
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 *
10 * Copyright (c) 2010-2015 Matt Bryson
11 * Dual licensed under the MIT or GPL Version 2 licenses.
12 *
13 */
14
15(function(factory) {
16	if (typeof define === 'function' && define.amd && define.amd.jQuery) {
17		define(['jquery'], factory);
18	} else {
19		factory(jQuery);
20	}
21}(function($) {
22	"use strict";
23	var VERSION = "1.6.9",
24		LEFT = "left",
25		RIGHT = "right",
26		UP = "up",
27		DOWN = "down",
28		IN = "in",
29		OUT = "out",
30		NONE = "none",
31		AUTO = "auto",
32		SWIPE = "swipe",
33		PINCH = "pinch",
34		TAP = "tap",
35		DOUBLE_TAP = "doubletap",
36		LONG_TAP = "longtap",
37		HOLD = "hold",
38		HORIZONTAL = "horizontal",
39		VERTICAL = "vertical",
40		ALL_FINGERS = "all",
41		DOUBLE_TAP_THRESHOLD = 10,
42		PHASE_START = "start",
43		PHASE_MOVE = "move",
44		PHASE_END = "end",
45		PHASE_CANCEL = "cancel",
46		SUPPORTS_TOUCH = 'ontouchstart' in window,
47		SUPPORTS_POINTER_IE10 = window.navigator.msPointerEnabled && !window.navigator.pointerEnabled,
48		SUPPORTS_POINTER = window.navigator.pointerEnabled || window.navigator.msPointerEnabled,
49		PLUGIN_NS = 'TouchSwipe';
50	var defaults = {
51		fingers: 1,
52		threshold: 75,
53		cancelThreshold: null,
54		pinchThreshold: 20,
55		maxTimeThreshold: null,
56		fingerReleaseThreshold: 250,
57		longTapThreshold: 500,
58		doubleTapThreshold: 200,
59		swipe: null,
60		swipeLeft: null,
61		swipeRight: null,
62		swipeUp: null,
63		swipeDown: null,
64		swipeStatus: null,
65		pinchIn: null,
66		pinchOut: null,
67		pinchStatus: null,
68		click: null,
69		tap: null,
70		doubleTap: null,
71		longTap: null,
72		hold: null,
73		triggerOnTouchEnd: true,
74		triggerOnTouchLeave: false,
75		allowPageScroll: "auto",
76		fallbackToMouseEvents: true,
77		excludedElements: "label, button, input, select, textarea, a, .noSwipe",
78		preventDefaultEvents: true
79	};
80	$.fn.swipe = function(method) {
81		var $this = $(this),
82			plugin = $this.data(PLUGIN_NS);
83		if (plugin && typeof method === 'string') {
84			if (plugin[method]) {
85				return plugin[method].apply(this, Array.prototype.slice.call(arguments, 1));
86			} else {
87				$.error('Method ' + method + ' does not exist on jQuery.swipe');
88			}
89		} else if (!plugin && (typeof method === 'object' || !method)) {
90			return init.apply(this, arguments);
91		}
92		return $this;
93	};
94	$.fn.swipe.version = VERSION;
95	$.fn.swipe.defaults = defaults;
96	$.fn.swipe.phases = {
97		PHASE_START: PHASE_START,
98		PHASE_MOVE: PHASE_MOVE,
99		PHASE_END: PHASE_END,
100		PHASE_CANCEL: PHASE_CANCEL
101	};
102	$.fn.swipe.directions = {
103		LEFT: LEFT,
104		RIGHT: RIGHT,
105		UP: UP,
106		DOWN: DOWN,
107		IN: IN,
108		OUT: OUT
109	};
110	$.fn.swipe.pageScroll = {
111		NONE: NONE,
112		HORIZONTAL: HORIZONTAL,
113		VERTICAL: VERTICAL,
114		AUTO: AUTO
115	};
116	$.fn.swipe.fingers = {
117		ONE: 1,
118		TWO: 2,
119		THREE: 3,
120		ALL: ALL_FINGERS
121	};
122
123	function init(options) {
124		if (options && (options.allowPageScroll === undefined && (options.swipe !== undefined || options.swipeStatus !== undefined))) {
125			options.allowPageScroll = NONE;
126		}
127		if (options.click !== undefined && options.tap === undefined) {
128			options.tap = options.click;
129		}
130		if (!options) {
131			options = {};
132		}
133		options = $.extend({}, $.fn.swipe.defaults, options);
134		return this.each(function() {
135			var $this = $(this);
136			var plugin = $this.data(PLUGIN_NS);
137			if (!plugin) {
138				plugin = new TouchSwipe(this, options);
139				$this.data(PLUGIN_NS, plugin);
140			}
141		});
142	}
143
144	function TouchSwipe(element, options) {
145		var useTouchEvents = (SUPPORTS_TOUCH || SUPPORTS_POINTER || !options.fallbackToMouseEvents),
146			START_EV = useTouchEvents ? (SUPPORTS_POINTER ? (SUPPORTS_POINTER_IE10 ? 'MSPointerDown' : 'pointerdown') : 'touchstart') : 'mousedown',
147			MOVE_EV = useTouchEvents ? (SUPPORTS_POINTER ? (SUPPORTS_POINTER_IE10 ? 'MSPointerMove' : 'pointermove') : 'touchmove') : 'mousemove',
148			END_EV = useTouchEvents ? (SUPPORTS_POINTER ? (SUPPORTS_POINTER_IE10 ? 'MSPointerUp' : 'pointerup') : 'touchend') : 'mouseup',
149			LEAVE_EV = useTouchEvents ? null : 'mouseleave',
150			CANCEL_EV = (SUPPORTS_POINTER ? (SUPPORTS_POINTER_IE10 ? 'MSPointerCancel' : 'pointercancel') : 'touchcancel');
151		var distance = 0,
152			direction = null,
153			duration = 0,
154			startTouchesDistance = 0,
155			endTouchesDistance = 0,
156			pinchZoom = 1,
157			pinchDistance = 0,
158			pinchDirection = 0,
159			maximumsMap = null;
160		var $element = $(element);
161		var phase = "start";
162		var fingerCount = 0;
163		var fingerData = null;
164		var startTime = 0,
165			endTime = 0,
166			previousTouchEndTime = 0,
167			previousTouchFingerCount = 0,
168			doubleTapStartTime = 0;
169		var singleTapTimeout = null,
170			holdTimeout = null;
171		try {
172			$element.bind(START_EV, touchStart);
173			$element.bind(CANCEL_EV, touchCancel);
174		} catch (e) {
175			$.error('events not supported ' + START_EV + ',' + CANCEL_EV + ' on jQuery.swipe');
176		}
177		this.enable = function() {
178			$element.bind(START_EV, touchStart);
179			$element.bind(CANCEL_EV, touchCancel);
180			return $element;
181		};
182		this.disable = function() {
183			removeListeners();
184			return $element;
185		};
186		this.destroy = function() {
187			removeListeners();
188			$element.data(PLUGIN_NS, null);
189			$element = null;
190		};
191		this.option = function(property, value) {
192			if (options[property] !== undefined) {
193				if (value === undefined) {
194					return options[property];
195				} else {
196					options[property] = value;
197				}
198			} else {
199				$.error('Option ' + property + ' does not exist on jQuery.swipe.options');
200			}
201			return null;
202		}
203
204		function touchStart(jqEvent) {
205			if (getTouchInProgress())
206				return;
207			if ($(jqEvent.target).closest(options.excludedElements, $element).length > 0)
208				return;
209			var event = jqEvent.originalEvent ? jqEvent.originalEvent : jqEvent;
210			var ret, touches = event.touches,
211				evt = touches ? touches[0] : event;
212			phase = PHASE_START;
213			if (touches) {
214				fingerCount = touches.length;
215			} else {
216				jqEvent.preventDefault();
217			}
218			distance = 0;
219			direction = null;
220			pinchDirection = null;
221			duration = 0;
222			startTouchesDistance = 0;
223			endTouchesDistance = 0;
224			pinchZoom = 1;
225			pinchDistance = 0;
226			fingerData = createAllFingerData();
227			maximumsMap = createMaximumsData();
228			cancelMultiFingerRelease();
229			if (!touches || (fingerCount === options.fingers || options.fingers === ALL_FINGERS) || hasPinches()) {
230				createFingerData(0, evt);
231				startTime = getTimeStamp();
232				if (fingerCount == 2) {
233					createFingerData(1, touches[1]);
234					startTouchesDistance = endTouchesDistance = calculateTouchesDistance(fingerData[0].start, fingerData[1].start);
235				}
236				if (options.swipeStatus || options.pinchStatus) {
237					ret = triggerHandler(event, phase);
238				}
239			} else {
240				ret = false;
241			}
242			if (ret === false) {
243				phase = PHASE_CANCEL;
244				triggerHandler(event, phase);
245				return ret;
246			} else {
247				if (options.hold) {
248					holdTimeout = setTimeout($.proxy(function() {
249						$element.trigger('hold', [event.target]);
250						if (options.hold) {
251							ret = options.hold.call($element, event, event.target);
252						}
253					}, this), options.longTapThreshold);
254				}
255				setTouchInProgress(true);
256			}
257			return null;
258		};
259
260		function touchMove(jqEvent) {
261			var event = jqEvent.originalEvent ? jqEvent.originalEvent : jqEvent;
262			if (phase === PHASE_END || phase === PHASE_CANCEL || inMultiFingerRelease())
263				return;
264			var ret, touches = event.touches,
265				evt = touches ? touches[0] : event;
266			var currentFinger = updateFingerData(evt);
267			endTime = getTimeStamp();
268			if (touches) {
269				fingerCount = touches.length;
270			}
271			if (options.hold)
272				clearTimeout(holdTimeout);
273			phase = PHASE_MOVE;
274			if (fingerCount == 2) {
275				if (startTouchesDistance == 0) {
276					createFingerData(1, touches[1]);
277					startTouchesDistance = endTouchesDistance = calculateTouchesDistance(fingerData[0].start, fingerData[1].start);
278				} else {
279					updateFingerData(touches[1]);
280					endTouchesDistance = calculateTouchesDistance(fingerData[0].end, fingerData[1].end);
281					pinchDirection = calculatePinchDirection(fingerData[0].end, fingerData[1].end);
282				}
283				pinchZoom = calculatePinchZoom(startTouchesDistance, endTouchesDistance);
284				pinchDistance = Math.abs(startTouchesDistance - endTouchesDistance);
285			}
286			if ((fingerCount === options.fingers || options.fingers === ALL_FINGERS) || !touches || hasPinches()) {
287				direction = calculateDirection(currentFinger.start, currentFinger.end);
288				validateDefaultEvent(jqEvent, direction);
289				distance = calculateDistance(currentFinger.start, currentFinger.end);
290				duration = calculateDuration();
291				setMaxDistance(direction, distance);
292				if (options.swipeStatus || options.pinchStatus) {
293					ret = triggerHandler(event, phase);
294				}
295				if (!options.triggerOnTouchEnd || options.triggerOnTouchLeave) {
296					var inBounds = true;
297					if (options.triggerOnTouchLeave) {
298						var bounds = getbounds(this);
299						inBounds = isInBounds(currentFinger.end, bounds);
300					}
301					if (!options.triggerOnTouchEnd && inBounds) {
302						phase = getNextPhase(PHASE_MOVE);
303					} else if (options.triggerOnTouchLeave && !inBounds) {
304						phase = getNextPhase(PHASE_END);
305					}
306					if (phase == PHASE_CANCEL || phase == PHASE_END) {
307						triggerHandler(event, phase);
308					}
309				}
310			} else {
311				phase = PHASE_CANCEL;
312				triggerHandler(event, phase);
313			}
314			if (ret === false) {
315				phase = PHASE_CANCEL;
316				triggerHandler(event, phase);
317			}
318		}
319
320		function touchEnd(jqEvent) {
321			var event = jqEvent.originalEvent ? jqEvent.originalEvent : jqEvent,
322				touches = event.touches;
323			if (touches) {
324				if (touches.length) {
325					startMultiFingerRelease();
326					return true;
327				}
328			}
329			if (inMultiFingerRelease()) {
330				fingerCount = previousTouchFingerCount;
331			}
332			endTime = getTimeStamp();
333			duration = calculateDuration();
334			if (didSwipeBackToCancel() || !validateSwipeDistance()) {
335				phase = PHASE_CANCEL;
336				triggerHandler(event, phase);
337			} else if (options.triggerOnTouchEnd || (options.triggerOnTouchEnd == false && phase === PHASE_MOVE)) {
338				jqEvent.preventDefault();
339				phase = PHASE_END;
340				triggerHandler(event, phase);
341			} else if (!options.triggerOnTouchEnd && hasTap()) {
342				phase = PHASE_END;
343				triggerHandlerForGesture(event, phase, TAP);
344			} else if (phase === PHASE_MOVE) {
345				phase = PHASE_CANCEL;
346				triggerHandler(event, phase);
347			}
348			setTouchInProgress(false);
349			return null;
350		}
351
352		function touchCancel() {
353			fingerCount = 0;
354			endTime = 0;
355			startTime = 0;
356			startTouchesDistance = 0;
357			endTouchesDistance = 0;
358			pinchZoom = 1;
359			cancelMultiFingerRelease();
360			setTouchInProgress(false);
361		}
362
363		function touchLeave(jqEvent) {
364			var event = jqEvent.originalEvent ? jqEvent.originalEvent : jqEvent;
365			if (options.triggerOnTouchLeave) {
366				phase = getNextPhase(PHASE_END);
367				triggerHandler(event, phase);
368			}
369		}
370
371		function removeListeners() {
372			$element.unbind(START_EV, touchStart);
373			$element.unbind(CANCEL_EV, touchCancel);
374			$element.unbind(MOVE_EV, touchMove);
375			$element.unbind(END_EV, touchEnd);
376			if (LEAVE_EV) {
377				$element.unbind(LEAVE_EV, touchLeave);
378			}
379			setTouchInProgress(false);
380		}
381
382		function getNextPhase(currentPhase) {
383			var nextPhase = currentPhase;
384			var validTime = validateSwipeTime();
385			var validDistance = validateSwipeDistance();
386			var didCancel = didSwipeBackToCancel();
387			if (!validTime || didCancel) {
388				nextPhase = PHASE_CANCEL;
389			} else if (validDistance && currentPhase == PHASE_MOVE && (!options.triggerOnTouchEnd || options.triggerOnTouchLeave)) {
390				nextPhase = PHASE_END;
391			} else if (!validDistance && currentPhase == PHASE_END && options.triggerOnTouchLeave) {
392				nextPhase = PHASE_CANCEL;
393			}
394			return nextPhase;
395		}
396
397		function triggerHandler(event, phase) {
398			var ret, touches = event.touches;
399			if ((didSwipe() || hasSwipes()) || (didPinch() || hasPinches())) {
400				if (didSwipe() || hasSwipes()) {
401					ret = triggerHandlerForGesture(event, phase, SWIPE);
402				}
403				if ((didPinch() || hasPinches()) && ret !== false) {
404					ret = triggerHandlerForGesture(event, phase, PINCH);
405				}
406			} else {
407				if (didDoubleTap() && ret !== false) {
408					ret = triggerHandlerForGesture(event, phase, DOUBLE_TAP);
409				} else if (didLongTap() && ret !== false) {
410					ret = triggerHandlerForGesture(event, phase, LONG_TAP);
411				} else if (didTap() && ret !== false) {
412					ret = triggerHandlerForGesture(event, phase, TAP);
413				}
414			}
415			if (phase === PHASE_CANCEL) {
416				touchCancel(event);
417			}
418			if (phase === PHASE_END) {
419				if (touches) {
420					if (!touches.length) {
421						touchCancel(event);
422					}
423				} else {
424					touchCancel(event);
425				}
426			}
427			return ret;
428		}
429
430		function triggerHandlerForGesture(event, phase, gesture) {
431			var ret;
432			if (gesture == SWIPE) {
433				$element.trigger('swipeStatus', [phase, direction || null, distance || 0, duration || 0, fingerCount, fingerData]);
434				if (options.swipeStatus) {
435					ret = options.swipeStatus.call($element, event, phase, direction || null, distance || 0, duration || 0, fingerCount, fingerData);
436					if (ret === false) return false;
437				}
438				if (phase == PHASE_END && validateSwipe()) {
439					$element.trigger('swipe', [direction, distance, duration, fingerCount, fingerData]);
440					if (options.swipe) {
441						ret = options.swipe.call($element, event, direction, distance, duration, fingerCount, fingerData);
442						if (ret === false) return false;
443					}
444					switch (direction) {
445						case LEFT:
446							$element.trigger('swipeLeft', [direction, distance, duration, fingerCount, fingerData]);
447							if (options.swipeLeft) {
448								ret = options.swipeLeft.call($element, event, direction, distance, duration, fingerCount, fingerData);
449							}
450							break;
451						case RIGHT:
452							$element.trigger('swipeRight', [direction, distance, duration, fingerCount, fingerData]);
453							if (options.swipeRight) {
454								ret = options.swipeRight.call($element, event, direction, distance, duration, fingerCount, fingerData);
455							}
456							break;
457						case UP:
458							$element.trigger('swipeUp', [direction, distance, duration, fingerCount, fingerData]);
459							if (options.swipeUp) {
460								ret = options.swipeUp.call($element, event, direction, distance, duration, fingerCount, fingerData);
461							}
462							break;
463						case DOWN:
464							$element.trigger('swipeDown', [direction, distance, duration, fingerCount, fingerData]);
465							if (options.swipeDown) {
466								ret = options.swipeDown.call($element, event, direction, distance, duration, fingerCount, fingerData);
467							}
468							break;
469					}
470				}
471			}
472			if (gesture == PINCH) {
473				$element.trigger('pinchStatus', [phase, pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData]);
474				if (options.pinchStatus) {
475					ret = options.pinchStatus.call($element, event, phase, pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData);
476					if (ret === false) return false;
477				}
478				if (phase == PHASE_END && validatePinch()) {
479					switch (pinchDirection) {
480						case IN:
481							$element.trigger('pinchIn', [pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData]);
482							if (options.pinchIn) {
483								ret = options.pinchIn.call($element, event, pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData);
484							}
485							break;
486						case OUT:
487							$element.trigger('pinchOut', [pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData]);
488							if (options.pinchOut) {
489								ret = options.pinchOut.call($element, event, pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData);
490							}
491							break;
492					}
493				}
494			}
495			if (gesture == TAP) {
496				if (phase === PHASE_CANCEL || phase === PHASE_END) {
497					clearTimeout(singleTapTimeout);
498					clearTimeout(holdTimeout);
499					if (hasDoubleTap() && !inDoubleTap()) {
500						doubleTapStartTime = getTimeStamp();
501						singleTapTimeout = setTimeout($.proxy(function() {
502							doubleTapStartTime = null;
503							$element.trigger('tap', [event.target]);
504							if (options.tap) {
505								ret = options.tap.call($element, event, event.target);
506							}
507						}, this), options.doubleTapThreshold);
508					} else {
509						doubleTapStartTime = null;
510						$element.trigger('tap', [event.target]);
511						if (options.tap) {
512							ret = options.tap.call($element, event, event.target);
513						}
514					}
515				}
516			} else if (gesture == DOUBLE_TAP) {
517				if (phase === PHASE_CANCEL || phase === PHASE_END) {
518					clearTimeout(singleTapTimeout);
519					doubleTapStartTime = null;
520					$element.trigger('doubletap', [event.target]);
521					if (options.doubleTap) {
522						ret = options.doubleTap.call($element, event, event.target);
523					}
524				}
525			} else if (gesture == LONG_TAP) {
526				if (phase === PHASE_CANCEL || phase === PHASE_END) {
527					clearTimeout(singleTapTimeout);
528					doubleTapStartTime = null;
529					$element.trigger('longtap', [event.target]);
530					if (options.longTap) {
531						ret = options.longTap.call($element, event, event.target);
532					}
533				}
534			}
535			return ret;
536		}
537
538		function validateSwipeDistance() {
539			var valid = true;
540			if (options.threshold !== null) {
541				valid = distance >= options.threshold;
542			}
543			return valid;
544		}
545
546		function didSwipeBackToCancel() {
547			var cancelled = false;
548			if (options.cancelThreshold !== null && direction !== null) {
549				cancelled = (getMaxDistance(direction) - distance) >= options.cancelThreshold;
550			}
551			return cancelled;
552		}
553
554		function validatePinchDistance() {
555			if (options.pinchThreshold !== null) {
556				return pinchDistance >= options.pinchThreshold;
557			}
558			return true;
559		}
560
561		function validateSwipeTime() {
562			var result;
563			if (options.maxTimeThreshold) {
564				if (duration >= options.maxTimeThreshold) {
565					result = false;
566				} else {
567					result = true;
568				}
569			} else {
570				result = true;
571			}
572			return result;
573		}
574
575		function validateDefaultEvent(jqEvent, direction) {
576			if (options.preventDefaultEvents === false) {
577				return;
578			}
579			if (options.allowPageScroll === NONE) {
580				jqEvent.preventDefault();
581			} else {
582				var auto = options.allowPageScroll === AUTO;
583				switch (direction) {
584					case LEFT:
585						if ((options.swipeLeft && auto) || (!auto && options.allowPageScroll != HORIZONTAL)) {
586							jqEvent.preventDefault();
587						}
588						break;
589					case RIGHT:
590						if ((options.swipeRight && auto) || (!auto && options.allowPageScroll != HORIZONTAL)) {
591							jqEvent.preventDefault();
592						}
593						break;
594					case UP:
595						if ((options.swipeUp && auto) || (!auto && options.allowPageScroll != VERTICAL)) {
596							jqEvent.preventDefault();
597						}
598						break;
599					case DOWN:
600						if ((options.swipeDown && auto) || (!auto && options.allowPageScroll != VERTICAL)) {
601							jqEvent.preventDefault();
602						}
603						break;
604				}
605			}
606		}
607
608		function validatePinch() {
609			var hasCorrectFingerCount = validateFingers();
610			var hasEndPoint = validateEndPoint();
611			var hasCorrectDistance = validatePinchDistance();
612			return hasCorrectFingerCount && hasEndPoint && hasCorrectDistance;
613		}
614
615		function hasPinches() {
616			return !!(options.pinchStatus || options.pinchIn || options.pinchOut);
617		}
618
619		function didPinch() {
620			return !!(validatePinch() && hasPinches());
621		}
622
623		function validateSwipe() {
624			var hasValidTime = validateSwipeTime();
625			var hasValidDistance = validateSwipeDistance();
626			var hasCorrectFingerCount = validateFingers();
627			var hasEndPoint = validateEndPoint();
628			var didCancel = didSwipeBackToCancel();
629			var valid = !didCancel && hasEndPoint && hasCorrectFingerCount && hasValidDistance && hasValidTime;
630			return valid;
631		}
632
633		function hasSwipes() {
634			return !!(options.swipe || options.swipeStatus || options.swipeLeft || options.swipeRight || options.swipeUp || options.swipeDown);
635		}
636
637		function didSwipe() {
638			return !!(validateSwipe() && hasSwipes());
639		}
640
641		function validateFingers() {
642			return ((fingerCount === options.fingers || options.fingers === ALL_FINGERS) || !SUPPORTS_TOUCH);
643		}
644
645		function validateEndPoint() {
646			return fingerData[0].end.x !== 0;
647		}
648
649		function hasTap() {
650			return !!(options.tap);
651		}
652
653		function hasDoubleTap() {
654			return !!(options.doubleTap);
655		}
656
657		function hasLongTap() {
658			return !!(options.longTap);
659		}
660
661		function validateDoubleTap() {
662			if (doubleTapStartTime == null) {
663				return false;
664			}
665			var now = getTimeStamp();
666			return (hasDoubleTap() && ((now - doubleTapStartTime) <= options.doubleTapThreshold));
667		}
668
669		function inDoubleTap() {
670			return validateDoubleTap();
671		}
672
673		function validateTap() {
674			return ((fingerCount === 1 || !SUPPORTS_TOUCH) && (isNaN(distance) || distance < options.threshold));
675		}
676
677		function validateLongTap() {
678			return ((duration > options.longTapThreshold) && (distance < DOUBLE_TAP_THRESHOLD));
679		}
680
681		function didTap() {
682			return !!(validateTap() && hasTap());
683		}
684
685		function didDoubleTap() {
686			return !!(validateDoubleTap() && hasDoubleTap());
687		}
688
689		function didLongTap() {
690			return !!(validateLongTap() && hasLongTap());
691		}
692
693		function startMultiFingerRelease() {
694			previousTouchEndTime = getTimeStamp();
695			previousTouchFingerCount = event.touches.length + 1;
696		}
697
698		function cancelMultiFingerRelease() {
699			previousTouchEndTime = 0;
700			previousTouchFingerCount = 0;
701		}
702
703		function inMultiFingerRelease() {
704			var withinThreshold = false;
705			if (previousTouchEndTime) {
706				var diff = getTimeStamp() - previousTouchEndTime
707				if (diff <= options.fingerReleaseThreshold) {
708					withinThreshold = true;
709				}
710			}
711			return withinThreshold;
712		}
713
714		function getTouchInProgress() {
715			return !!($element.data(PLUGIN_NS + '_intouch') === true);
716		}
717
718		function setTouchInProgress(val) {
719			if (val === true) {
720				$element.bind(MOVE_EV, touchMove);
721				$element.bind(END_EV, touchEnd);
722				if (LEAVE_EV) {
723					$element.bind(LEAVE_EV, touchLeave);
724				}
725			} else {
726				$element.unbind(MOVE_EV, touchMove, false);
727				$element.unbind(END_EV, touchEnd, false);
728				if (LEAVE_EV) {
729					$element.unbind(LEAVE_EV, touchLeave, false);
730				}
731			}
732			$element.data(PLUGIN_NS + '_intouch', val === true);
733		}
734
735		function createFingerData(index, evt) {
736			var id = evt.identifier !== undefined ? evt.identifier : 0;
737			fingerData[index].identifier = id;
738			fingerData[index].start.x = fingerData[index].end.x = evt.pageX || evt.clientX;
739			fingerData[index].start.y = fingerData[index].end.y = evt.pageY || evt.clientY;
740			return fingerData[index];
741		}
742
743		function updateFingerData(evt) {
744			var id = evt.identifier !== undefined ? evt.identifier : 0;
745			var f = getFingerData(id);
746			f.end.x = evt.pageX || evt.clientX;
747			f.end.y = evt.pageY || evt.clientY;
748			return f;
749		}
750
751		function getFingerData(id) {
752			for (var i = 0; i < fingerData.length; i++) {
753				if (fingerData[i].identifier == id) {
754					return fingerData[i];
755				}
756			}
757		}
758
759		function createAllFingerData() {
760			var fingerData = [];
761			for (var i = 0; i <= 5; i++) {
762				fingerData.push({
763					start: {
764						x: 0,
765						y: 0
766					},
767					end: {
768						x: 0,
769						y: 0
770					},
771					identifier: 0
772				});
773			}
774			return fingerData;
775		}
776
777		function setMaxDistance(direction, distance) {
778			distance = Math.max(distance, getMaxDistance(direction));
779			maximumsMap[direction].distance = distance;
780		}
781
782		function getMaxDistance(direction) {
783			if (maximumsMap[direction]) return maximumsMap[direction].distance;
784			return undefined;
785		}
786
787		function createMaximumsData() {
788			var maxData = {};
789			maxData[LEFT] = createMaximumVO(LEFT);
790			maxData[RIGHT] = createMaximumVO(RIGHT);
791			maxData[UP] = createMaximumVO(UP);
792			maxData[DOWN] = createMaximumVO(DOWN);
793			return maxData;
794		}
795
796		function createMaximumVO(dir) {
797			return {
798				direction: dir,
799				distance: 0
800			}
801		}
802
803		function calculateDuration() {
804			return endTime - startTime;
805		}
806
807		function calculateTouchesDistance(startPoint, endPoint) {
808			var diffX = Math.abs(startPoint.x - endPoint.x);
809			var diffY = Math.abs(startPoint.y - endPoint.y);
810			return Math.round(Math.sqrt(diffX * diffX + diffY * diffY));
811		}
812
813		function calculatePinchZoom(startDistance, endDistance) {
814			var percent = (endDistance / startDistance) * 1;
815			return percent.toFixed(2);
816		}
817
818		function calculatePinchDirection() {
819			if (pinchZoom < 1) {
820				return OUT;
821			} else {
822				return IN;
823			}
824		}
825
826		function calculateDistance(startPoint, endPoint) {
827			return Math.round(Math.sqrt(Math.pow(endPoint.x - startPoint.x, 2) + Math.pow(endPoint.y - startPoint.y, 2)));
828		}
829
830		function calculateAngle(startPoint, endPoint) {
831			var x = startPoint.x - endPoint.x;
832			var y = endPoint.y - startPoint.y;
833			var r = Math.atan2(y, x);
834			var angle = Math.round(r * 180 / Math.PI);
835			if (angle < 0) {
836				angle = 360 - Math.abs(angle);
837			}
838			return angle;
839		}
840
841		function calculateDirection(startPoint, endPoint) {
842			var angle = calculateAngle(startPoint, endPoint);
843			if ((angle <= 45) && (angle >= 0)) {
844				return LEFT;
845			} else if ((angle <= 360) && (angle >= 315)) {
846				return LEFT;
847			} else if ((angle >= 135) && (angle <= 225)) {
848				return RIGHT;
849			} else if ((angle > 45) && (angle < 135)) {
850				return DOWN;
851			} else {
852				return UP;
853			}
854		}
855
856		function getTimeStamp() {
857			var now = new Date();
858			return now.getTime();
859		}
860
861		function getbounds(el) {
862			el = $(el);
863			var offset = el.offset();
864			var bounds = {
865				left: offset.left,
866				right: offset.left + el.outerWidth(),
867				top: offset.top,
868				bottom: offset.top + el.outerHeight()
869			}
870			return bounds;
871		}
872
873		function isInBounds(point, bounds) {
874			return (point.x > bounds.left && point.x < bounds.right && point.y > bounds.top && point.y < bounds.bottom);
875		};
876	}
877}));

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.