PageSourceSearch

https://www.hsander-immobilien.de/files/theme/js/scripts.js

js hsander-immobilien.de collected 2026-10-07 04:59:14 UTC 107,015 bytes, 2,721 lines download raw bytes

1var settings_ankerpunkte = true; // true/false
2var settings_buttonup = true; // true/false
3var settings_autotarget = true; // true/false
4var settings_iframe2video = true; // true/false
5var settings_countup = true; // true/false
6var settings_b3slider = true; // true/false
7var settings_autotarget = true; // true/false
8var settings_immoautoformfill = true; // true/false
9var settings_potrait_no_title_popup = true; // true/false
10
11/*!
12 *
13 * https://raw.githubusercontent.com/mattbryson/TouchSwipe-Jquery-Plugin/master/jquery.touchSwipe.js
14 * 
15 * 
16 * @fileOverview TouchSwipe - jQuery Plugin
17 * @version 1.6.18
18 *
19 * @author Matt Bryson http://www.github.com/mattbryson
20 * @see https://github.com/mattbryson/TouchSwipe-Jquery-Plugin
21 * @see http://labs.rampinteractive.co.uk/touchSwipe/
22 * @see http://plugins.jquery.com/project/touchSwipe
23 * @license
24 * Copyright (c) 2010-2015 Matt Bryson
25 * Dual licensed under the MIT or GPL Version 2 licenses.
26 *
27 */
28
29/*
30 *
31 * Changelog
32 * $Date: 2010-12-12 (Wed, 12 Dec 2010) $
33 * $version: 1.0.0
34 * $version: 1.0.1 - removed multibyte comments
35 *
36 * $Date: 2011-21-02 (Mon, 21 Feb 2011) $
37 * $version: 1.1.0 	- added allowPageScroll property to allow swiping and scrolling of page
38 *					- changed handler signatures so one handler can be used for multiple events
39 * $Date: 2011-23-02 (Wed, 23 Feb 2011) $
40 * $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.
41 *					- 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.
42 * $version: 1.2.1 	- removed console log!
43 *
44 * $version: 1.2.2 	- Fixed bug where scope was not preserved in callback methods.
45 *
46 * $Date: 2011-28-04 (Thurs, 28 April 2011) $
47 * $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.
48 *
49 * $Date: 2011-27-09 (Tues, 27 September 2011) $
50 * $version: 1.2.5 	- Added support for testing swipes with mouse on desktop browser (thanks to https://github.com/joelhy)
51 *
52 * $Date: 2012-14-05 (Mon, 14 May 2012) $
53 * $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
54 *
55 * $Date: 2012-05-06 (Tues, 05 June 2012) $
56 * $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.
57 *
58 * $Date: 2012-05-06 (Tues, 05 June 2012) $
59 * $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.
60 *
61 * $Date: 2012-06-06 (Wed, 06 June 2012) $
62 * $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
63 *
64 * $Date: 2012-05-06 (Fri, 05 June 2012) $
65 * $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.
66 *
67 * $Date: 2012-29-07 (Sun, 29 July 2012) $
68 * $version: 1.3.2	- Added fallbackToMouseEvents option to NOT capture mouse events on non touch devices.
69 * 			- Added "all" fingers value to the fingers property, so any combination of fingers triggers the swipe, allowing event handlers to check the finger count
70 *
71 * $Date: 2012-09-08 (Thurs, 9 Aug 2012) $
72 * $version: 1.3.3	- Code tidy prep for minefied version
73 *
74 * $Date: 2012-04-10 (wed, 4 Oct 2012) $
75 * $version: 1.4.0	- Added pinch support, pinchIn and pinchOut
76 *
77 * $Date: 2012-11-10 (Thurs, 11 Oct 2012) $
78 * $version: 1.5.0	- Added excludedElements, a jquery selector that specifies child elements that do NOT trigger swipes. By default, this is .noSwipe
79 *
80 * $Date: 2012-22-10 (Mon, 22 Oct 2012) $
81 * $version: 1.5.1	- Fixed bug with jQuery 1.8 and trailing comma in excludedElements
82 *					- Fixed bug with IE and eventPreventDefault()
83 * $Date: 2013-01-12 (Fri, 12 Jan 2013) $
84 * $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.
85 *					- made the demo site all static local HTML pages so they can be run locally by a developer
86 *					- added jsDoc comments and added documentation for the plugin
87 *					- code tidy
88 *					- added triggerOnTouchLeave property that will end the event when the user swipes off the element.
89 * $Date: 2013-03-23 (Sat, 23 Mar 2013) $
90 * $version: 1.6.1	- Added support for ie8 touch events
91 * $version: 1.6.2	- Added support for events binding with on / off / bind in jQ for all callback names.
92 *                   - Deprecated the 'click' handler in favour of tap.
93 *                   - added cancelThreshold property
94 *                   - added option method to update init options at runtime
95 * $version 1.6.3    - added doubletap, longtap events and longTapThreshold, doubleTapThreshold property
96 *
97 * $Date: 2013-04-04 (Thurs, 04 April 2013) $
98 * $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.
99 *
100 * $Date: 2013-08-24 (Sat, 24 Aug 2013) $
101 * $version 1.6.5    - Merged a few pull requests fixing various bugs, added AMD support.
102 *
103 * $Date: 2014-06-04 (Wed, 04 June 2014) $
104 * $version 1.6.6 	- Merge of pull requests.
105 *    				- IE10 touch support
106 *    				- Only prevent default event handling on valid swipe
107 *    				- Separate license/changelog comment
108 *    				- Detect if the swipe is valid at the end of the touch event.
109 *    				- Pass fingerdata to event handlers.
110 *    				- Add 'hold' gesture
111 *    				- Be more tolerant about the tap distance
112 *    				- Typos and minor fixes
113 *
114 * $Date: 2015-22-01 (Thurs, 22 Jan 2015) $
115 * $version 1.6.7    - Added patch from https://github.com/mattbryson/TouchSwipe-Jquery-Plugin/issues/206 to fix memory leak
116 *
117 * $Date: 2015-2-2 (Mon, 2 Feb 2015) $
118 * $version 1.6.8    - Added preventDefaultEvents option to proxy events regardless.
119 *					- Fixed issue with swipe and pinch not triggering at the same time
120 *
121 * $Date: 2015-9-6 (Tues, 9 June 2015) $
122 * $version 1.6.9    - Added PR from jdalton/hybrid to fix pointer events
123 *					- Added scrolling demo
124 *					- Added version property to plugin
125 *
126 * $Date: 2015-1-10 (Wed, 1 October 2015) $
127 * $version 1.6.10    - Added PR from beatspace to fix tap events
128 * $version 1.6.11    - Added PRs from indri-indri ( Doc tidyup), kkirsche ( Bower tidy up ), UziTech (preventDefaultEvents fixes )
129 *					 - Allowed setting multiple options via .swipe("options", options_hash) and more simply .swipe(options_hash) or exisitng instances
130 * $version 1.6.12    - Fixed bug with multi finger releases above 2 not triggering events
131 *
132 * $Date: 2015-12-18 (Fri, 18 December 2015) $
133 * $version 1.6.13    - Added PRs
134 *                    - Fixed #267 allowPageScroll not working correctly
135 * $version 1.6.14    - Fixed #220 / #248 doubletap not firing with swipes, #223 commonJS compatible
136 * $version 1.6.15    - More bug fixes
137 *
138 * $Date: 2016-04-29 (Fri, 29 April 2016) $
139 * $version 1.6.16    - Swipes with 0 distance now allow default events to trigger.  So tapping any form elements or A tags will allow default interaction, but swiping will trigger a swipe.
140                        Removed the a, input, select etc from the excluded Children list as the 0 distance tap solves that issue.
141* $Date: 2016-05-19  (Fri, 29 April 2016) $
142* $version 1.6.17     - Fixed context issue when calling instance methods via $("selector").swipe("method");
143* $version 1.6.18     - now honors fallbackToMouseEvents=false for MS Pointer events when a Mouse is used.
144
145 */
146
147/**
148 * See (http://jquery.com/).
149 * @name $
150 * @class
151 * See the jQuery Library  (http://jquery.com/) for full details.  This just
152 * documents the function and classes that are added to jQuery by this plug-in.
153 */
154
155/**
156 * See (http://jquery.com/)
157 * @name fn
158 * @class
159 * See the jQuery Library  (http://jquery.com/) for full details.  This just
160 * documents the function and classes that are added to jQuery by this plug-in.
161 * @memberOf $
162 */
163
164
165(function (factory) {
166    if (typeof define === 'function' && define.amd && define.amd.jQuery) {
167        // AMD. Register as anonymous module.
168        define(['jquery'], factory);
169    } else if (typeof module !== 'undefined' && module.exports) {
170        // CommonJS Module
171        factory(require("jquery"));
172    } else {
173        // Browser globals.
174        factory(jQuery);
175    }
176}(function ($) {
177    "use strict";
178
179    //Constants
180    var VERSION = "1.6.18",
181        LEFT = "left",
182        RIGHT = "right",
183        UP = "up",
184        DOWN = "down",
185        IN = "in",
186        OUT = "out",
187
188        NONE = "none",
189        AUTO = "auto",
190
191        SWIPE = "swipe",
192        PINCH = "pinch",
193        TAP = "tap",
194        DOUBLE_TAP = "doubletap",
195        LONG_TAP = "longtap",
196        HOLD = "hold",
197
198        HORIZONTAL = "horizontal",
199        VERTICAL = "vertical",
200
201        ALL_FINGERS = "all",
202
203        DOUBLE_TAP_THRESHOLD = 10,
204
205        PHASE_START = "start",
206        PHASE_MOVE = "move",
207        PHASE_END = "end",
208        PHASE_CANCEL = "cancel",
209
210        SUPPORTS_TOUCH = 'ontouchstart' in window,
211
212        SUPPORTS_POINTER_IE10 = window.navigator.msPointerEnabled && !window.PointerEvent && !SUPPORTS_TOUCH,
213
214        SUPPORTS_POINTER = (window.PointerEvent || window.navigator.msPointerEnabled) && !SUPPORTS_TOUCH,
215
216        PLUGIN_NS = 'TouchSwipe';
217
218
219
220    /**
221    * The default configuration, and available options to configure touch swipe with.
222    * You can set the default values by updating any of the properties prior to instantiation.
223    * @name $.fn.swipe.defaults
224    * @namespace
225    * @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.
226    * @property {int} [threshold=75] The number of pixels that the user must move their finger by before it is considered a swipe.
227    * @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.
228    * @property {int} [pinchThreshold=20] The number of pixels that the user must pinch their finger by before it is considered a pinch.
229    * @property {int} [maxTimeThreshold=null] Time, in milliseconds, between touchStart and touchEnd must NOT exceed in order to be considered a swipe.
230    * @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.
231    * @property {int} [longTapThreshold=500] Time in milliseconds between tap and release for a long tap
232    * @property {int} [doubleTapThreshold=200] Time in milliseconds between 2 taps to count as a double tap
233    * @property {function} [swipe=null] A handler to catch all swipes. See {@link $.fn.swipe#event:swipe}
234    * @property {function} [swipeLeft=null] A handler that is triggered for "left" swipes. See {@link $.fn.swipe#event:swipeLeft}
235    * @property {function} [swipeRight=null] A handler that is triggered for "right" swipes. See {@link $.fn.swipe#event:swipeRight}
236    * @property {function} [swipeUp=null] A handler that is triggered for "up" swipes. See {@link $.fn.swipe#event:swipeUp}
237    * @property {function} [swipeDown=null] A handler that is triggered for "down" swipes. See {@link $.fn.swipe#event:swipeDown}
238    * @property {function} [swipeStatus=null] A handler triggered for every phase of the swipe. See {@link $.fn.swipe#event:swipeStatus}
239    * @property {function} [pinchIn=null] A handler triggered for pinch in events. See {@link $.fn.swipe#event:pinchIn}
240    * @property {function} [pinchOut=null] A handler triggered for pinch out events. See {@link $.fn.swipe#event:pinchOut}
241    * @property {function} [pinchStatus=null] A handler triggered for every phase of a pinch. See {@link $.fn.swipe#event:pinchStatus}
242    * @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.
243    * @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}
244    * @property {function} [longTap=null] A handler triggered when a user long taps on the item. The delay between start and end can be set with the longTapThreshold property. See {@link $.fn.swipe.defaults#longTapThreshold}
245    * @property (function) [hold=null] A handler triggered when a user reaches longTapThreshold on the item. See {@link $.fn.swipe.defaults#longTapThreshold}
246    * @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.
247    * @property {boolean} [triggerOnTouchLeave=false] If true, then when the user leaves the swipe object, the swipe will end and trigger appropriate handlers.
248    * @property {string|undefined} [allowPageScroll='auto'] How the browser handles page scrolls when the user is swiping on a touchSwipe object. See {@link $.fn.swipe.pageScroll}.  <br/><br/>
249    									<code>"auto"</code> : all undefined swipes will cause the page to scroll in that direction. <br/>
250    									<code>"none"</code> : the page will not scroll when user swipes. <br/>
251    									<code>"horizontal"</code> : will force page to scroll on horizontal swipes. <br/>
252    									<code>"vertical"</code> : will force page to scroll on vertical swipes. <br/>
253    * @property {boolean} [fallbackToMouseEvents=true] If true mouse events are used when run on a non touch device, false will stop swipes being triggered by mouse events on non touch devices.
254    * @property {string} [excludedElements=".noSwipe"] A jquery selector that specifies child elements that do NOT trigger swipes. By default this excludes elements with the class .noSwipe .
255    * @property {boolean} [preventDefaultEvents=true] by default default events are cancelled, so the page doesn't move.  You can disable this so both native events fire as well as your handlers.
256
257    */
258    var defaults = {
259        fingers: 1,
260        threshold: 75,
261        cancelThreshold: null,
262        pinchThreshold: 20,
263        maxTimeThreshold: null,
264        fingerReleaseThreshold: 250,
265        longTapThreshold: 500,
266        doubleTapThreshold: 200,
267        swipe: null,
268        swipeLeft: null,
269        swipeRight: null,
270        swipeUp: null,
271        swipeDown: null,
272        swipeStatus: null,
273        pinchIn: null,
274        pinchOut: null,
275        pinchStatus: null,
276        click: null, //Deprecated since 1.6.2
277        tap: null,
278        doubleTap: null,
279        longTap: null,
280        hold: null,
281        triggerOnTouchEnd: true,
282        triggerOnTouchLeave: false,
283        allowPageScroll: "auto",
284        fallbackToMouseEvents: true,
vendor: 62,077 bytes, lines 285-1912
285        excludedElements: ".noSwipe",
286        preventDefaultEvents: true
287    };
288
289
290
291    /**
292     * Applies TouchSwipe behaviour to one or more jQuery objects.
293     * The TouchSwipe plugin can be instantiated via this method, or methods within
294     * TouchSwipe can be executed via this method as per jQuery plugin architecture.
295     * An existing plugin can have its options changed simply by re calling .swipe(options)
296     * @see TouchSwipe
297     * @class
298     * @param {Mixed} method If the current DOMNode is a TouchSwipe object, and <code>method</code> is a TouchSwipe method, then
299     * the <code>method</code> is executed, and any following arguments are passed to the TouchSwipe method.
300     * If <code>method</code> is an object, then the TouchSwipe class is instantiated on the current DOMNode, passing the
301     * configuration properties defined in the object. See TouchSwipe
302     *
303     */
304    $.fn.swipe = function (method) {
305        var $this = $(this),
306            plugin = $this.data(PLUGIN_NS);
307
308        //Check if we are already instantiated and trying to execute a method
309        if (plugin && typeof method === 'string') {
310            if (plugin[method]) {
311                return plugin[method].apply(plugin, Array.prototype.slice.call(arguments, 1));
312            } else {
313                $.error('Method ' + method + ' does not exist on jQuery.swipe');
314            }
315        }
316
317        //Else update existing plugin with new options hash
318        else if (plugin && typeof method === 'object') {
319            plugin['option'].apply(plugin, arguments);
320        }
321
322        //Else not instantiated and trying to pass init object (or nothing)
323        else if (!plugin && (typeof method === 'object' || !method)) {
324            return init.apply(this, arguments);
325        }
326
327        return $this;
328    };
329
330    /**
331     * The version of the plugin
332     * @readonly
333     */
334    $.fn.swipe.version = VERSION;
335
336
337
338    //Expose our defaults so a user could override the plugin defaults
339    $.fn.swipe.defaults = defaults;
340
341    /**
342     * The phases that a touch event goes through.  The <code>phase</code> is passed to the event handlers.
343     * These properties are read only, attempting to change them will not alter the values passed to the event handlers.
344     * @namespace
345     * @readonly
346     * @property {string} PHASE_START Constant indicating the start phase of the touch event. Value is <code>"start"</code>.
347     * @property {string} PHASE_MOVE Constant indicating the move phase of the touch event. Value is <code>"move"</code>.
348     * @property {string} PHASE_END Constant indicating the end phase of the touch event. Value is <code>"end"</code>.
349     * @property {string} PHASE_CANCEL Constant indicating the cancel phase of the touch event. Value is <code>"cancel"</code>.
350     */
351    $.fn.swipe.phases = {
352        PHASE_START: PHASE_START,
353        PHASE_MOVE: PHASE_MOVE,
354        PHASE_END: PHASE_END,
355        PHASE_CANCEL: PHASE_CANCEL
356    };
357
358    /**
359     * The direction constants that are passed to the event handlers.
360     * These properties are read only, attempting to change them will not alter the values passed to the event handlers.
361     * @namespace
362     * @readonly
363     * @property {string} LEFT Constant indicating the left direction. Value is <code>"left"</code>.
364     * @property {string} RIGHT Constant indicating the right direction. Value is <code>"right"</code>.
365     * @property {string} UP Constant indicating the up direction. Value is <code>"up"</code>.
366     * @property {string} DOWN Constant indicating the down direction. Value is <code>"cancel"</code>.
367     * @property {string} IN Constant indicating the in direction. Value is <code>"in"</code>.
368     * @property {string} OUT Constant indicating the out direction. Value is <code>"out"</code>.
369     */
370    $.fn.swipe.directions = {
371        LEFT: LEFT,
372        RIGHT: RIGHT,
373        UP: UP,
374        DOWN: DOWN,
375        IN: IN,
376        OUT: OUT
377    };
378
379    /**
380     * The page scroll constants that can be used to set the value of <code>allowPageScroll</code> option
381     * These properties are read only
382     * @namespace
383     * @readonly
384     * @see $.fn.swipe.defaults#allowPageScroll
385     * @property {string} NONE Constant indicating no page scrolling is allowed. Value is <code>"none"</code>.
386     * @property {string} HORIZONTAL Constant indicating horizontal page scrolling is allowed. Value is <code>"horizontal"</code>.
387     * @property {string} VERTICAL Constant indicating vertical page scrolling is allowed. Value is <code>"vertical"</code>.
388     * @property {string} AUTO Constant indicating either horizontal or vertical will be allowed, depending on the swipe handlers registered. Value is <code>"auto"</code>.
389     */
390    $.fn.swipe.pageScroll = {
391        NONE: NONE,
392        HORIZONTAL: HORIZONTAL,
393        VERTICAL: VERTICAL,
394        AUTO: AUTO
395    };
396
397    /**
398     * Constants representing the number of fingers used in a swipe.  These are used to set both the value of <code>fingers</code> in the
399     * options object, as well as the value of the <code>fingers</code> event property.
400     * These properties are read only, attempting to change them will not alter the values passed to the event handlers.
401     * @namespace
402     * @readonly
403     * @see $.fn.swipe.defaults#fingers
404     * @property {string} ONE Constant indicating 1 finger is to be detected / was detected. Value is <code>1</code>.
405     * @property {string} TWO Constant indicating 2 fingers are to be detected / were detected. Value is <code>2</code>.
406     * @property {string} THREE Constant indicating 3 finger are to be detected / were detected. Value is <code>3</code>.
407     * @property {string} FOUR Constant indicating 4 finger are to be detected / were detected. Not all devices support this. Value is <code>4</code>.
408     * @property {string} FIVE Constant indicating 5 finger are to be detected / were detected. Not all devices support this. Value is <code>5</code>.
409     * @property {string} ALL Constant indicating any combination of finger are to be detected.  Value is <code>"all"</code>.
410     */
411    $.fn.swipe.fingers = {
412        ONE: 1,
413        TWO: 2,
414        THREE: 3,
415        FOUR: 4,
416        FIVE: 5,
417        ALL: ALL_FINGERS
418    };
419
420    /**
421     * Initialise the plugin for each DOM element matched
422     * This creates a new instance of the main TouchSwipe class for each DOM element, and then
423     * saves a reference to that instance in the elements data property.
424     * @internal
425     */
426    function init(options) {
427        //Prep and extend the options
428        if (options && (options.allowPageScroll === undefined && (options.swipe !== undefined || options.swipeStatus !== undefined))) {
429            options.allowPageScroll = NONE;
430        }
431
432        //Check for deprecated options
433        //Ensure that any old click handlers are assigned to the new tap, unless we have a tap
434        if (options.click !== undefined && options.tap === undefined) {
435            options.tap = options.click;
436        }
437
438        if (!options) {
439            options = {};
440        }
441
442        //pass empty object so we dont modify the defaults
443        options = $.extend({}, $.fn.swipe.defaults, options);
444
445        //For each element instantiate the plugin
446        return this.each(function () {
447            var $this = $(this);
448
449            //Check we havent already initialised the plugin
450            var plugin = $this.data(PLUGIN_NS);
451
452            if (!plugin) {
453                plugin = new TouchSwipe(this, options);
454                $this.data(PLUGIN_NS, plugin);
455            }
456        });
457    }
458
459    /**
460     * Main TouchSwipe Plugin Class.
461     * Do not use this to construct your TouchSwipe object, use the jQuery plugin method $.fn.swipe(); {@link $.fn.swipe}
462     * @private
463     * @name TouchSwipe
464     * @param {DOMNode} element The HTML DOM object to apply to plugin to
465     * @param {Object} options The options to configure the plugin with.  @link {$.fn.swipe.defaults}
466     * @see $.fh.swipe.defaults
467     * @see $.fh.swipe
468     * @class
469     */
470    function TouchSwipe(element, options) {
471
472        //take a local/instacne level copy of the options - should make it this.options really...
473        var options = $.extend({}, options);
474
475        var useTouchEvents = (SUPPORTS_TOUCH || SUPPORTS_POINTER || !options.fallbackToMouseEvents),
476            START_EV = useTouchEvents ? (SUPPORTS_POINTER ? (SUPPORTS_POINTER_IE10 ? 'MSPointerDown' : 'pointerdown') : 'touchstart') : 'mousedown',
477            MOVE_EV = useTouchEvents ? (SUPPORTS_POINTER ? (SUPPORTS_POINTER_IE10 ? 'MSPointerMove' : 'pointermove') : 'touchmove') : 'mousemove',
478            END_EV = useTouchEvents ? (SUPPORTS_POINTER ? (SUPPORTS_POINTER_IE10 ? 'MSPointerUp' : 'pointerup') : 'touchend') : 'mouseup',
479            LEAVE_EV = useTouchEvents ? (SUPPORTS_POINTER ? 'mouseleave' : null) : 'mouseleave', //we manually detect leave on touch devices, so null event here
480            CANCEL_EV = (SUPPORTS_POINTER ? (SUPPORTS_POINTER_IE10 ? 'MSPointerCancel' : 'pointercancel') : 'touchcancel');
481
482
483
484        //touch properties
485        var distance = 0,
486            direction = null,
487            currentDirection = null,
488            duration = 0,
489            startTouchesDistance = 0,
490            endTouchesDistance = 0,
491            pinchZoom = 1,
492            pinchDistance = 0,
493            pinchDirection = 0,
494            maximumsMap = null;
495
496
497
498        //jQuery wrapped element for this instance
499        var $element = $(element);
500
501        //Current phase of th touch cycle
502        var phase = "start";
503
504        // the current number of fingers being used.
505        var fingerCount = 0;
506
507        //track mouse points / delta
508        var fingerData = {};
509
510        //track times
511        var startTime = 0,
512            endTime = 0,
513            previousTouchEndTime = 0,
514            fingerCountAtRelease = 0,
515            doubleTapStartTime = 0;
516
517        //Timeouts
518        var singleTapTimeout = null,
519            holdTimeout = null;
520
521        // Add gestures to all swipable areas if supported
522        try {
523            $element.on(START_EV, touchStart);
524            $element.on(CANCEL_EV, touchCancel);
525        } catch (e) {
526            $.error('events not supported ' + START_EV + ',' + CANCEL_EV + ' on jQuery.swipe');
527        }
528
529        //
530        //Public methods
531        //
532
533        /**
534         * re-enables the swipe plugin with the previous configuration
535         * @function
536         * @name $.fn.swipe#enable
537         * @return {DOMNode} The Dom element that was registered with TouchSwipe
538         * @example $("#element").swipe("enable");
539         */
540        this.enable = function () {
541            //Incase we are already enabled, clean up...
542            this.disable();
543            $element.on(START_EV, touchStart);
544            $element.on(CANCEL_EV, touchCancel);
545            return $element;
546        };
547
548        /**
549         * disables the swipe plugin
550         * @function
551         * @name $.fn.swipe#disable
552         * @return {DOMNode} The Dom element that is now registered with TouchSwipe
553         * @example $("#element").swipe("disable");
554         */
555        this.disable = function () {
556            removeListeners();
557            return $element;
558        };
559
560        /**
561         * Destroy the swipe plugin completely. To use any swipe methods, you must re initialise the plugin.
562         * @function
563         * @name $.fn.swipe#destroy
564         * @example $("#element").swipe("destroy");
565         */
566        this.destroy = function () {
567            removeListeners();
568            $element.data(PLUGIN_NS, null);
569            $element = null;
570        };
571
572
573        /**
574         * Allows run time updating of the swipe configuration options.
575         * @function
576         * @name $.fn.swipe#option
577         * @param {String} property The option property to get or set, or a has of multiple options to set
578         * @param {Object} [value] The value to set the property to
579         * @return {Object} If only a property name is passed, then that property value is returned. If nothing is passed the current options hash is returned.
580         * @example $("#element").swipe("option", "threshold"); // return the threshold
581         * @example $("#element").swipe("option", "threshold", 100); // set the threshold after init
582         * @example $("#element").swipe("option", {threshold:100, fingers:3} ); // set multiple properties after init
583         * @example $("#element").swipe({threshold:100, fingers:3} ); // set multiple properties after init - the "option" method is optional!
584         * @example $("#element").swipe("option"); // Return the current options hash
585         * @see $.fn.swipe.defaults
586         *
587         */
588        this.option = function (property, value) {
589
590            if (typeof property === 'object') {
591                options = $.extend(options, property);
592            } else if (options[property] !== undefined) {
593                if (value === undefined) {
594                    return options[property];
595                } else {
596                    options[property] = value;
597                }
598            } else if (!property) {
599                return options;
600            } else {
601                $.error('Option ' + property + ' does not exist on jQuery.swipe.options');
602            }
603
604            return null;
605        }
606
607
608
609        //
610        // Private methods
611        //
612
613        //
614        // EVENTS
615        //
616        /**
617         * Event handler for a touch start event.
618         * Stops the default click event from triggering and stores where we touched
619         * @inner
620         * @param {object} jqEvent The normalised jQuery event object.
621         */
622        function touchStart(jqEvent) {
623
624            //If we already in a touch event (a finger already in use) then ignore subsequent ones..
625            if (getTouchInProgress()) {
626                return;
627            }
628
629            //Check if this element matches any in the excluded elements selectors,  or its parent is excluded, if so, DON'T swipe
630            if ($(jqEvent.target).closest(options.excludedElements, $element).length > 0) {
631                return;
632            }
633
634            //As we use Jquery bind for events, we need to target the original event object
635            //If these events are being programmatically triggered, we don't have an original event object, so use the Jq one.
636            var event = jqEvent.originalEvent ? jqEvent.originalEvent : jqEvent;
637
638
639            //If we have a pointer event, whoes type is 'mouse' and we have said NO mouse events, then dont do anything.
640            if (event.pointerType && event.pointerType == "mouse" && options.fallbackToMouseEvents == false) {
641                return;
642            };
643
644            var ret,
645                touches = event.touches,
646                evt = touches ? touches[0] : event;
647
648            phase = PHASE_START;
649
650            //If we support touches, get the finger count
651            if (touches) {
652                // get the total number of fingers touching the screen
653                fingerCount = touches.length;
654            }
655            //Else this is the desktop, so stop the browser from dragging content
656            else if (options.preventDefaultEvents !== false) {
657                jqEvent.preventDefault(); //call this on jq event so we are cross browser
658            }
659
660            //clear vars..
661            distance = 0;
662            direction = null;
663            currentDirection = null;
664            pinchDirection = null;
665            duration = 0;
666            startTouchesDistance = 0;
667            endTouchesDistance = 0;
668            pinchZoom = 1;
669            pinchDistance = 0;
670            maximumsMap = createMaximumsData();
671            cancelMultiFingerRelease();
672
673            //Create the default finger data
674            createFingerData(0, evt);
675
676            // check the number of fingers is what we are looking for, or we are capturing pinches
677            if (!touches || (fingerCount === options.fingers || options.fingers === ALL_FINGERS) || hasPinches()) {
678                // get the coordinates of the touch
679                startTime = getTimeStamp();
680
681                if (fingerCount == 2) {
682                    //Keep track of the initial pinch distance, so we can calculate the diff later
683                    //Store second finger data as start
684                    createFingerData(1, touches[1]);
685                    startTouchesDistance = endTouchesDistance = calculateTouchesDistance(fingerData[0].start, fingerData[1].start);
686                }
687
688                if (options.swipeStatus || options.pinchStatus) {
689                    ret = triggerHandler(event, phase);
690                }
691            } else {
692                //A touch with more or less than the fingers we are looking for, so cancel
693                ret = false;
694            }
695
696            //If we have a return value from the users handler, then return and cancel
697            if (ret === false) {
698                phase = PHASE_CANCEL;
699                triggerHandler(event, phase);
700                return ret;
701            } else {
702                if (options.hold) {
703                    holdTimeout = setTimeout($.proxy(function () {
704                        //Trigger the event
705                        $element.trigger('hold', [event.target]);
706                        //Fire the callback
707                        if (options.hold) {
708                            ret = options.hold.call($element, event, event.target);
709                        }
710                    }, this), options.longTapThreshold);
711                }
712
713                setTouchInProgress(true);
714            }
715
716            return null;
717        };
718
719
720
721        /**
722         * Event handler for a touch move event.
723         * If we change fingers during move, then cancel the event
724         * @inner
725         * @param {object} jqEvent The normalised jQuery event object.
726         */
727        function touchMove(jqEvent) {
728
729            //As we use Jquery bind for events, we need to target the original event object
730            //If these events are being programmatically triggered, we don't have an original event object, so use the Jq one.
731            var event = jqEvent.originalEvent ? jqEvent.originalEvent : jqEvent;
732
733            //If we are ending, cancelling, or within the threshold of 2 fingers being released, don't track anything..
734            if (phase === PHASE_END || phase === PHASE_CANCEL || inMultiFingerRelease())
735                return;
736
737            var ret,
738                touches = event.touches,
739                evt = touches ? touches[0] : event;
740
741
742            //Update the  finger data
743            var currentFinger = updateFingerData(evt);
744            endTime = getTimeStamp();
745
746            if (touches) {
747                fingerCount = touches.length;
748            }
749
750            if (options.hold) {
751                clearTimeout(holdTimeout);
752            }
753
754            phase = PHASE_MOVE;
755
756            //If we have 2 fingers get Touches distance as well
757            if (fingerCount == 2) {
758
759                //Keep track of the initial pinch distance, so we can calculate the diff later
760                //We do this here as well as the start event, in case they start with 1 finger, and the press 2 fingers
761                if (startTouchesDistance == 0) {
762                    //Create second finger if this is the first time...
763                    createFingerData(1, touches[1]);
764
765                    startTouchesDistance = endTouchesDistance = calculateTouchesDistance(fingerData[0].start, fingerData[1].start);
766                } else {
767                    //Else just update the second finger
768                    updateFingerData(touches[1]);
769
770                    endTouchesDistance = calculateTouchesDistance(fingerData[0].end, fingerData[1].end);
771                    pinchDirection = calculatePinchDirection(fingerData[0].end, fingerData[1].end);
772                }
773
774                pinchZoom = calculatePinchZoom(startTouchesDistance, endTouchesDistance);
775                pinchDistance = Math.abs(startTouchesDistance - endTouchesDistance);
776            }
777
778            if ((fingerCount === options.fingers || options.fingers === ALL_FINGERS) || !touches || hasPinches()) {
779
780                //The overall direction of the swipe. From start to now.
781                direction = calculateDirection(currentFinger.start, currentFinger.end);
782
783                //The immediate direction of the swipe, direction between the last movement and this one.
784                currentDirection = calculateDirection(currentFinger.last, currentFinger.end);
785
786                //Check if we need to prevent default event (page scroll / pinch zoom) or not
787                validateDefaultEvent(jqEvent, currentDirection);
788
789                //Distance and duration are all off the main finger
790                distance = calculateDistance(currentFinger.start, currentFinger.end);
791                duration = calculateDuration();
792
793                //Cache the maximum distance we made in this direction
794                setMaxDistance(direction, distance);
795
796                //Trigger status handler
797                ret = triggerHandler(event, phase);
798
799
800                //If we trigger end events when threshold are met, or trigger events when touch leaves element
801                if (!options.triggerOnTouchEnd || options.triggerOnTouchLeave) {
802
803                    var inBounds = true;
804
805                    //If checking if we leave the element, run the bounds check (we can use touchleave as its not supported on webkit)
806                    if (options.triggerOnTouchLeave) {
807                        var bounds = getbounds(this);
808                        inBounds = isInBounds(currentFinger.end, bounds);
809                    }
810
811                    //Trigger end handles as we swipe if thresholds met or if we have left the element if the user has asked to check these..
812                    if (!options.triggerOnTouchEnd && inBounds) {
813                        phase = getNextPhase(PHASE_MOVE);
814                    }
815                    //We end if out of bounds here, so set current phase to END, and check if its modified
816                    else if (options.triggerOnTouchLeave && !inBounds) {
817                        phase = getNextPhase(PHASE_END);
818                    }
819
820                    if (phase == PHASE_CANCEL || phase == PHASE_END) {
821                        triggerHandler(event, phase);
822                    }
823                }
824            } else {
825                phase = PHASE_CANCEL;
826                triggerHandler(event, phase);
827            }
828
829            if (ret === false) {
830                phase = PHASE_CANCEL;
831                triggerHandler(event, phase);
832            }
833        }
834
835
836
837
838        /**
839         * Event handler for a touch end event.
840         * Calculate the direction and trigger events
841         * @inner
842         * @param {object} jqEvent The normalised jQuery event object.
843         */
844        function touchEnd(jqEvent) {
845            //As we use Jquery bind for events, we need to target the original event object
846            //If these events are being programmatically triggered, we don't have an original event object, so use the Jq one.
847            var event = jqEvent.originalEvent ? jqEvent.originalEvent : jqEvent,
848                touches = event.touches;
849
850            //If we are still in a touch with the device wait a fraction and see if the other finger comes up
851            //if it does within the threshold, then we treat it as a multi release, not a single release and end the touch / swipe
852            if (touches) {
853                if (touches.length && !inMultiFingerRelease()) {
854                    startMultiFingerRelease(event);
855                    return true;
856                } else if (touches.length && inMultiFingerRelease()) {
857                    return true;
858                }
859            }
860
861            //If a previous finger has been released, check how long ago, if within the threshold, then assume it was a multifinger release.
862            //This is used to allow 2 fingers to release fractionally after each other, whilst maintaining the event as containing 2 fingers, not 1
863            if (inMultiFingerRelease()) {
864                fingerCount = fingerCountAtRelease;
865            }
866
867            //Set end of swipe
868            endTime = getTimeStamp();
869
870            //Get duration incase move was never fired
871            duration = calculateDuration();
872
873            //If we trigger handlers at end of swipe OR, we trigger during, but they didnt trigger and we are still in the move phase
874            if (didSwipeBackToCancel() || !validateSwipeDistance()) {
875                phase = PHASE_CANCEL;
876                triggerHandler(event, phase);
877            } else if (options.triggerOnTouchEnd || (options.triggerOnTouchEnd === false && phase === PHASE_MOVE)) {
878                //call this on jq event so we are cross browser
879                if (options.preventDefaultEvents !== false && jqEvent.cancelable !== false) {
880                    jqEvent.preventDefault();
881                }
882                phase = PHASE_END;
883                triggerHandler(event, phase);
884            }
885            //Special cases - A tap should always fire on touch end regardless,
886            //So here we manually trigger the tap end handler by itself
887            //We dont run trigger handler as it will re-trigger events that may have fired already
888            else if (!options.triggerOnTouchEnd && hasTap()) {
889                //Trigger the pinch events...
890                phase = PHASE_END;
891                triggerHandlerForGesture(event, phase, TAP);
892            } else if (phase === PHASE_MOVE) {
893                phase = PHASE_CANCEL;
894                triggerHandler(event, phase);
895            }
896
897            setTouchInProgress(false);
898
899            return null;
900        }
901
902
903
904        /**
905         * Event handler for a touch cancel event.
906         * Clears current vars
907         * @inner
908         */
909        function touchCancel() {
910            // reset the variables back to default values
911            fingerCount = 0;
912            endTime = 0;
913            startTime = 0;
914            startTouchesDistance = 0;
915            endTouchesDistance = 0;
916            pinchZoom = 1;
917
918            //If we were in progress of tracking a possible multi touch end, then re set it.
919            cancelMultiFingerRelease();
920
921            setTouchInProgress(false);
922        }
923
924
925        /**
926         * Event handler for a touch leave event.
927         * This is only triggered on desktops, in touch we work this out manually
928         * as the touchleave event is not supported in webkit
929         * @inner
930         */
931        function touchLeave(jqEvent) {
932            //If these events are being programmatically triggered, we don't have an original event object, so use the Jq one.
933            var event = jqEvent.originalEvent ? jqEvent.originalEvent : jqEvent;
934
935            //If we have the trigger on leave property set....
936            if (options.triggerOnTouchLeave) {
937                phase = getNextPhase(PHASE_END);
938                triggerHandler(event, phase);
939            }
940        }
941
942        /**
943         * Removes all listeners that were associated with the plugin
944         * @inner
945         */
946        function removeListeners() {
947            $element.off(START_EV, touchStart);
948            $element.off(CANCEL_EV, touchCancel);
949            $element.off(MOVE_EV, touchMove);
950            $element.off(END_EV, touchEnd);
951
952            //we only have leave events on desktop, we manually calculate leave on touch as its not supported in webkit
953            if (LEAVE_EV) {
954                $element.off(LEAVE_EV, touchLeave);
955            }
956
957            setTouchInProgress(false);
958        }
959
960
961        /**
962         * Checks if the time and distance thresholds have been met, and if so then the appropriate handlers are fired.
963         */
964        function getNextPhase(currentPhase) {
965
966            var nextPhase = currentPhase;
967
968            // Ensure we have valid swipe (under time and over distance  and check if we are out of bound...)
969            var validTime = validateSwipeTime();
970            var validDistance = validateSwipeDistance();
971            var didCancel = didSwipeBackToCancel();
972
973            //If we have exceeded our time, then cancel
974            if (!validTime || didCancel) {
975                nextPhase = PHASE_CANCEL;
976            }
977            //Else if we are moving, and have reached distance then end
978            else if (validDistance && currentPhase == PHASE_MOVE && (!options.triggerOnTouchEnd || options.triggerOnTouchLeave)) {
979                nextPhase = PHASE_END;
980            }
981            //Else if we have ended by leaving and didn't reach distance, then cancel
982            else if (!validDistance && currentPhase == PHASE_END && options.triggerOnTouchLeave) {
983                nextPhase = PHASE_CANCEL;
984            }
985
986            return nextPhase;
987        }
988
989
990        /**
991         * Trigger the relevant event handler
992         * 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"
993         * @param {object} event the original event object
994         * @param {string} phase the phase of the swipe (start, end cancel etc) {@link $.fn.swipe.phases}
995         * @inner
996         */
997        function triggerHandler(event, phase) {
998
999
1000
1001            var ret,
1002                touches = event.touches;
1003
1004            // SWIPE GESTURES
1005            if (didSwipe() || hasSwipes()) {
1006                ret = triggerHandlerForGesture(event, phase, SWIPE);
1007            }
1008
1009            // PINCH GESTURES (if the above didn't cancel)
1010            if ((didPinch() || hasPinches()) && ret !== false) {
1011                ret = triggerHandlerForGesture(event, phase, PINCH);
1012            }
1013
1014            // CLICK / TAP (if the above didn't cancel)
1015            if (didDoubleTap() && ret !== false) {
1016                //Trigger the tap events...
1017                ret = triggerHandlerForGesture(event, phase, DOUBLE_TAP);
1018            }
1019
1020            // CLICK / TAP (if the above didn't cancel)
1021            else if (didLongTap() && ret !== false) {
1022                //Trigger the tap events...
1023                ret = triggerHandlerForGesture(event, phase, LONG_TAP);
1024            }
1025
1026            // CLICK / TAP (if the above didn't cancel)
1027            else if (didTap() && ret !== false) {
1028                //Trigger the tap event..
1029                ret = triggerHandlerForGesture(event, phase, TAP);
1030            }
1031
1032
1033
1034            // If we are cancelling the gesture, then manually trigger the reset handler
1035            if (phase === PHASE_CANCEL) {
1036
1037                touchCancel(event);
1038            }
1039
1040
1041
1042
1043            // If we are ending the gesture, then manually trigger the reset handler IF all fingers are off
1044            if (phase === PHASE_END) {
1045                //If we support touch, then check that all fingers are off before we cancel
1046                if (touches) {
1047                    if (!touches.length) {
1048                        touchCancel(event);
1049                    }
1050                } else {
1051                    touchCancel(event);
1052                }
1053            }
1054
1055            return ret;
1056        }
1057
1058
1059
1060        /**
1061         * Trigger the relevant event handler
1062         * 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"
1063         * @param {object} event the original event object
1064         * @param {string} phase the phase of the swipe (start, end cancel etc) {@link $.fn.swipe.phases}
1065         * @param {string} gesture the gesture to trigger a handler for : PINCH or SWIPE {@link $.fn.swipe.gestures}
1066         * @return Boolean False, to indicate that the event should stop propagation, or void.
1067         * @inner
1068         */
1069        function triggerHandlerForGesture(event, phase, gesture) {
1070
1071            var ret;
1072
1073            //SWIPES....
1074            if (gesture == SWIPE) {
1075                //Trigger status every time..
1076                $element.trigger('swipeStatus', [phase, direction || null, distance || 0, duration || 0, fingerCount, fingerData, currentDirection]);
1077
1078                if (options.swipeStatus) {
1079                    ret = options.swipeStatus.call($element, event, phase, direction || null, distance || 0, duration || 0, fingerCount, fingerData, currentDirection);
1080                    //If the status cancels, then dont run the subsequent event handlers..
1081                    if (ret === false) return false;
1082                }
1083
1084                if (phase == PHASE_END && validateSwipe()) {
1085
1086                    //Cancel any taps that were in progress...
1087                    clearTimeout(singleTapTimeout);
1088                    clearTimeout(holdTimeout);
1089
1090                    $element.trigger('swipe', [direction, distance, duration, fingerCount, fingerData, currentDirection]);
1091
1092                    if (options.swipe) {
1093                        ret = options.swipe.call($element, event, direction, distance, duration, fingerCount, fingerData, currentDirection);
1094                        //If the status cancels, then dont run the subsequent event handlers..
1095                        if (ret === false) return false;
1096                    }
1097
1098                    //trigger direction specific event handlers
1099                    switch (direction) {
1100                        case LEFT:
1101                            $element.trigger('swipeLeft', [direction, distance, duration, fingerCount, fingerData, currentDirection]);
1102
1103                            if (options.swipeLeft) {
1104                                ret = options.swipeLeft.call($element, event, direction, distance, duration, fingerCount, fingerData, currentDirection);
1105                            }
1106                            break;
1107
1108                        case RIGHT:
1109                            $element.trigger('swipeRight', [direction, distance, duration, fingerCount, fingerData, currentDirection]);
1110
1111                            if (options.swipeRight) {
1112                                ret = options.swipeRight.call($element, event, direction, distance, duration, fingerCount, fingerData, currentDirection);
1113                            }
1114                            break;
1115
1116                        case UP:
1117                            $element.trigger('swipeUp', [direction, distance, duration, fingerCount, fingerData, currentDirection]);
1118
1119                            if (options.swipeUp) {
1120                                ret = options.swipeUp.call($element, event, direction, distance, duration, fingerCount, fingerData, currentDirection);
1121                            }
1122                            break;
1123
1124                        case DOWN:
1125                            $element.trigger('swipeDown', [direction, distance, duration, fingerCount, fingerData, currentDirection]);
1126
1127                            if (options.swipeDown) {
1128                                ret = options.swipeDown.call($element, event, direction, distance, duration, fingerCount, fingerData, currentDirection);
1129                            }
1130                            break;
1131                    }
1132                }
1133            }
1134
1135
1136            //PINCHES....
1137            if (gesture == PINCH) {
1138                $element.trigger('pinchStatus', [phase, pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData]);
1139
1140                if (options.pinchStatus) {
1141                    ret = options.pinchStatus.call($element, event, phase, pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData);
1142                    //If the status cancels, then dont run the subsequent event handlers..
1143                    if (ret === false) return false;
1144                }
1145
1146                if (phase == PHASE_END && validatePinch()) {
1147
1148                    switch (pinchDirection) {
1149                        case IN:
1150                            $element.trigger('pinchIn', [pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData]);
1151
1152                            if (options.pinchIn) {
1153                                ret = options.pinchIn.call($element, event, pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData);
1154                            }
1155                            break;
1156
1157                        case OUT:
1158                            $element.trigger('pinchOut', [pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData]);
1159
1160                            if (options.pinchOut) {
1161                                ret = options.pinchOut.call($element, event, pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData);
1162                            }
1163                            break;
1164                    }
1165                }
1166            }
1167
1168            if (gesture == TAP) {
1169                if (phase === PHASE_CANCEL || phase === PHASE_END) {
1170
1171                    clearTimeout(singleTapTimeout);
1172                    clearTimeout(holdTimeout);
1173
1174                    //If we are also looking for doubelTaps, wait incase this is one...
1175                    if (hasDoubleTap() && !inDoubleTap()) {
1176                        doubleTapStartTime = getTimeStamp();
1177
1178                        //Now wait for the double tap timeout, and trigger this single tap
1179                        //if its not cancelled by a double tap
1180                        singleTapTimeout = setTimeout($.proxy(function () {
1181                            doubleTapStartTime = null;
1182                            $element.trigger('tap', [event.target]);
1183
1184                            if (options.tap) {
1185                                ret = options.tap.call($element, event, event.target);
1186                            }
1187                        }, this), options.doubleTapThreshold);
1188
1189                    } else {
1190                        doubleTapStartTime = null;
1191                        $element.trigger('tap', [event.target]);
1192                        if (options.tap) {
1193                            ret = options.tap.call($element, event, event.target);
1194                        }
1195                    }
1196                }
1197            } else if (gesture == DOUBLE_TAP) {
1198                if (phase === PHASE_CANCEL || phase === PHASE_END) {
1199                    clearTimeout(singleTapTimeout);
1200                    clearTimeout(holdTimeout);
1201                    doubleTapStartTime = null;
1202                    $element.trigger('doubletap', [event.target]);
1203
1204                    if (options.doubleTap) {
1205                        ret = options.doubleTap.call($element, event, event.target);
1206                    }
1207                }
1208            } else if (gesture == LONG_TAP) {
1209                if (phase === PHASE_CANCEL || phase === PHASE_END) {
1210                    clearTimeout(singleTapTimeout);
1211                    doubleTapStartTime = null;
1212
1213                    $element.trigger('longtap', [event.target]);
1214                    if (options.longTap) {
1215                        ret = options.longTap.call($element, event, event.target);
1216                    }
1217                }
1218            }
1219
1220            return ret;
1221        }
1222
1223
1224        //
1225        // GESTURE VALIDATION
1226        //
1227
1228        /**
1229         * Checks the user has swipe far enough
1230         * @return Boolean if <code>threshold</code> has been set, return true if the threshold was met, else false.
1231         * If no threshold was set, then we return true.
1232         * @inner
1233         */
1234        function validateSwipeDistance() {
1235            var valid = true;
1236            //If we made it past the min swipe distance..
1237            if (options.threshold !== null) {
1238                valid = distance >= options.threshold;
1239            }
1240
1241            return valid;
1242        }
1243
1244        /**
1245         * Checks the user has swiped back to cancel.
1246         * @return Boolean if <code>cancelThreshold</code> has been set, return true if the cancelThreshold was met, else false.
1247         * If no cancelThreshold was set, then we return true.
1248         * @inner
1249         */
1250        function didSwipeBackToCancel() {
1251            var cancelled = false;
1252            if (options.cancelThreshold !== null && direction !== null) {
1253                cancelled = (getMaxDistance(direction) - distance) >= options.cancelThreshold;
1254            }
1255
1256            return cancelled;
1257        }
1258
1259        /**
1260         * Checks the user has pinched far enough
1261         * @return Boolean if <code>pinchThreshold</code> has been set, return true if the threshold was met, else false.
1262         * If no threshold was set, then we return true.
1263         * @inner
1264         */
1265        function validatePinchDistance() {
1266            if (options.pinchThreshold !== null) {
1267                return pinchDistance >= options.pinchThreshold;
1268            }
1269            return true;
1270        }
1271
1272        /**
1273         * Checks that the time taken to swipe meets the minimum / maximum requirements
1274         * @return Boolean
1275         * @inner
1276         */
1277        function validateSwipeTime() {
1278            var result;
1279            //If no time set, then return true
1280            if (options.maxTimeThreshold) {
1281                if (duration >= options.maxTimeThreshold) {
1282                    result = false;
1283                } else {
1284                    result = true;
1285                }
1286            } else {
1287                result = true;
1288            }
1289
1290            return result;
1291        }
1292
1293
1294        /**
1295         * Checks direction of the swipe and the value allowPageScroll to see if we should allow or prevent the default behaviour from occurring.
1296         * This will essentially allow page scrolling or not when the user is swiping on a touchSwipe object.
1297         * @param {object} jqEvent The normalised jQuery representation of the event object.
1298         * @param {string} direction The direction of the event. See {@link $.fn.swipe.directions}
1299         * @see $.fn.swipe.directions
1300         * @inner
1301         */
1302        function validateDefaultEvent(jqEvent, direction) {
1303
1304            //If the option is set, allways allow the event to bubble up (let user handle weirdness)
1305            if (options.preventDefaultEvents === false) {
1306                return;
1307            }
1308
1309            if (options.allowPageScroll === NONE) {
1310                jqEvent.preventDefault();
1311            } else {
1312                var auto = options.allowPageScroll === AUTO;
1313
1314                switch (direction) {
1315                    case LEFT:
1316                        if ((options.swipeLeft && auto) || (!auto && options.allowPageScroll != HORIZONTAL)) {
1317                            jqEvent.preventDefault();
1318                        }
1319                        break;
1320
1321                    case RIGHT:
1322                        if ((options.swipeRight && auto) || (!auto && options.allowPageScroll != HORIZONTAL)) {
1323                            jqEvent.preventDefault();
1324                        }
1325                        break;
1326
1327                    case UP:
1328                        if ((options.swipeUp && auto) || (!auto && options.allowPageScroll != VERTICAL)) {
1329                            jqEvent.preventDefault();
1330                        }
1331                        break;
1332
1333                    case DOWN:
1334                        if ((options.swipeDown && auto) || (!auto && options.allowPageScroll != VERTICAL)) {
1335                            jqEvent.preventDefault();
1336                        }
1337                        break;
1338
1339                    case NONE:
1340
1341                        break;
1342                }
1343            }
1344        }
1345
1346
1347        // PINCHES
1348        /**
1349         * Returns true of the current pinch meets the thresholds
1350         * @return Boolean
1351         * @inner
1352         */
1353        function validatePinch() {
1354            var hasCorrectFingerCount = validateFingers();
1355            var hasEndPoint = validateEndPoint();
1356            var hasCorrectDistance = validatePinchDistance();
1357            return hasCorrectFingerCount && hasEndPoint && hasCorrectDistance;
1358
1359        }
1360
1361        /**
1362         * Returns true if any Pinch events have been registered
1363         * @return Boolean
1364         * @inner
1365         */
1366        function hasPinches() {
1367            //Enure we dont return 0 or null for false values
1368            return !!(options.pinchStatus || options.pinchIn || options.pinchOut);
1369        }
1370
1371        /**
1372         * Returns true if we are detecting pinches, and have one
1373         * @return Boolean
1374         * @inner
1375         */
1376        function didPinch() {
1377            //Enure we dont return 0 or null for false values
1378            return !!(validatePinch() && hasPinches());
1379        }
1380
1381
1382
1383
1384        // SWIPES
1385        /**
1386         * Returns true if the current swipe meets the thresholds
1387         * @return Boolean
1388         * @inner
1389         */
1390        function validateSwipe() {
1391            //Check validity of swipe
1392            var hasValidTime = validateSwipeTime();
1393            var hasValidDistance = validateSwipeDistance();
1394            var hasCorrectFingerCount = validateFingers();
1395            var hasEndPoint = validateEndPoint();
1396            var didCancel = didSwipeBackToCancel();
1397
1398            // if the user swiped more than the minimum length, perform the appropriate action
1399            // hasValidDistance is null when no distance is set
1400            var valid = !didCancel && hasEndPoint && hasCorrectFingerCount && hasValidDistance && hasValidTime;
1401
1402            return valid;
1403        }
1404
1405        /**
1406         * Returns true if any Swipe events have been registered
1407         * @return Boolean
1408         * @inner
1409         */
1410        function hasSwipes() {
1411            //Enure we dont return 0 or null for false values
1412            return !!(options.swipe || options.swipeStatus || options.swipeLeft || options.swipeRight || options.swipeUp || options.swipeDown);
1413        }
1414
1415
1416        /**
1417         * Returns true if we are detecting swipes and have one
1418         * @return Boolean
1419         * @inner
1420         */
1421        function didSwipe() {
1422            //Enure we dont return 0 or null for false values
1423            return !!(validateSwipe() && hasSwipes());
1424        }
1425
1426        /**
1427         * Returns true if we have matched the number of fingers we are looking for
1428         * @return Boolean
1429         * @inner
1430         */
1431        function validateFingers() {
1432            //The number of fingers we want were matched, or on desktop we ignore
1433            return ((fingerCount === options.fingers || options.fingers === ALL_FINGERS) || !SUPPORTS_TOUCH);
1434        }
1435
1436        /**
1437         * Returns true if we have an end point for the swipe
1438         * @return Boolean
1439         * @inner
1440         */
1441        function validateEndPoint() {
1442            //We have an end value for the finger
1443            return fingerData[0].end.x !== 0;
1444        }
1445
1446        // TAP / CLICK
1447        /**
1448         * Returns true if a click / tap events have been registered
1449         * @return Boolean
1450         * @inner
1451         */
1452        function hasTap() {
1453            //Enure we dont return 0 or null for false values
1454            return !!(options.tap);
1455        }
1456
1457        /**
1458         * Returns true if a double tap events have been registered
1459         * @return Boolean
1460         * @inner
1461         */
1462        function hasDoubleTap() {
1463            //Enure we dont return 0 or null for false values
1464            return !!(options.doubleTap);
1465        }
1466
1467        /**
1468         * Returns true if any long tap events have been registered
1469         * @return Boolean
1470         * @inner
1471         */
1472        function hasLongTap() {
1473            //Enure we dont return 0 or null for false values
1474            return !!(options.longTap);
1475        }
1476
1477        /**
1478         * 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.
1479         * @return Boolean
1480         * @inner
1481         */
1482        function validateDoubleTap() {
1483            if (doubleTapStartTime == null) {
1484                return false;
1485            }
1486            var now = getTimeStamp();
1487            return (hasDoubleTap() && ((now - doubleTapStartTime) <= options.doubleTapThreshold));
1488        }
1489
1490        /**
1491         * 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.
1492         * @return Boolean
1493         * @inner
1494         */
1495        function inDoubleTap() {
1496            return validateDoubleTap();
1497        }
1498
1499
1500        /**
1501         * Returns true if we have a valid tap
1502         * @return Boolean
1503         * @inner
1504         */
1505        function validateTap() {
1506            return ((fingerCount === 1 || !SUPPORTS_TOUCH) && (isNaN(distance) || distance < options.threshold));
1507        }
1508
1509        /**
1510         * Returns true if we have a valid long tap
1511         * @return Boolean
1512         * @inner
1513         */
1514        function validateLongTap() {
1515            //slight threshold on moving finger
1516            return ((duration > options.longTapThreshold) && (distance < DOUBLE_TAP_THRESHOLD));
1517        }
1518
1519        /**
1520         * Returns true if we are detecting taps and have one
1521         * @return Boolean
1522         * @inner
1523         */
1524        function didTap() {
1525            //Enure we dont return 0 or null for false values
1526            return !!(validateTap() && hasTap());
1527        }
1528
1529
1530        /**
1531         * Returns true if we are detecting double taps and have one
1532         * @return Boolean
1533         * @inner
1534         */
1535        function didDoubleTap() {
1536            //Enure we dont return 0 or null for false values
1537            return !!(validateDoubleTap() && hasDoubleTap());
1538        }
1539
1540        /**
1541         * Returns true if we are detecting long taps and have one
1542         * @return Boolean
1543         * @inner
1544         */
1545        function didLongTap() {
1546            //Enure we dont return 0 or null for false values
1547            return !!(validateLongTap() && hasLongTap());
1548        }
1549
1550
1551
1552
1553        // MULTI FINGER TOUCH
1554        /**
1555         * Starts tracking the time between 2 finger releases, and keeps track of how many fingers we initially had up
1556         * @inner
1557         */
1558        function startMultiFingerRelease(event) {
1559            previousTouchEndTime = getTimeStamp();
1560            fingerCountAtRelease = event.touches.length + 1;
1561        }
1562
1563        /**
1564         * Cancels the tracking of time between 2 finger releases, and resets counters
1565         * @inner
1566         */
1567        function cancelMultiFingerRelease() {
1568            previousTouchEndTime = 0;
1569            fingerCountAtRelease = 0;
1570        }
1571
1572        /**
1573         * Checks if we are in the threshold between 2 fingers being released
1574         * @return Boolean
1575         * @inner
1576         */
1577        function inMultiFingerRelease() {
1578
1579            var withinThreshold = false;
1580
1581            if (previousTouchEndTime) {
1582                var diff = getTimeStamp() - previousTouchEndTime
1583                if (diff <= options.fingerReleaseThreshold) {
1584                    withinThreshold = true;
1585                }
1586            }
1587
1588            return withinThreshold;
1589        }
1590
1591
1592        /**
1593         * gets a data flag to indicate that a touch is in progress
1594         * @return Boolean
1595         * @inner
1596         */
1597        function getTouchInProgress() {
1598            //strict equality to ensure only true and false are returned
1599            return !!($element.data(PLUGIN_NS + '_intouch') === true);
1600        }
1601
1602        /**
1603         * Sets a data flag to indicate that a touch is in progress
1604         * @param {boolean} val The value to set the property to
1605         * @inner
1606         */
1607        function setTouchInProgress(val) {
1608
1609            //If destroy is called in an event handler, we have no el, and we have already cleaned up, so return.
1610            if (!$element) {
1611                return;
1612            }
1613
1614            //Add or remove event listeners depending on touch status
1615            if (val === true) {
1616                $element.on(MOVE_EV, touchMove);
1617                $element.on(END_EV, touchEnd);
1618
1619                //we only have leave events on desktop, we manually calcuate leave on touch as its not supported in webkit
1620                if (LEAVE_EV) {
1621                    $element.on(LEAVE_EV, touchLeave);
1622                }
1623            } else {
1624
1625                $element.off(MOVE_EV, touchMove, false);
1626                $element.off(END_EV, touchEnd, false);
1627
1628                //we only have leave events on desktop, we manually calcuate leave on touch as its not supported in webkit
1629                if (LEAVE_EV) {
1630                    $element.off(LEAVE_EV, touchLeave, false);
1631                }
1632            }
1633
1634
1635            //strict equality to ensure only true and false can update the value
1636            $element.data(PLUGIN_NS + '_intouch', val === true);
1637        }
1638
1639
1640        /**
1641         * Creates the finger data for the touch/finger in the event object.
1642         * @param {int} id The id to store the finger data under (usually the order the fingers were pressed)
1643         * @param {object} evt The event object containing finger data
1644         * @return finger data object
1645         * @inner
1646         */
1647        function createFingerData(id, evt) {
1648            var f = {
1649                start: {
1650                    x: 0,
1651                    y: 0
1652                },
1653                last: {
1654                    x: 0,
1655                    y: 0
1656                },
1657                end: {
1658                    x: 0,
1659                    y: 0
1660                }
1661            };
1662            f.start.x = f.last.x = f.end.x = evt.pageX || evt.clientX;
1663            f.start.y = f.last.y = f.end.y = evt.pageY || evt.clientY;
1664            fingerData[id] = f;
1665            return f;
1666        }
1667
1668        /**
1669         * Updates the finger data for a particular event object
1670         * @param {object} evt The event object containing the touch/finger data to upadte
1671         * @return a finger data object.
1672         * @inner
1673         */
1674        function updateFingerData(evt) {
1675            var id = evt.identifier !== undefined ? evt.identifier : 0;
1676            var f = getFingerData(id);
1677
1678            if (f === null) {
1679                f = createFingerData(id, evt);
1680            }
1681
1682            f.last.x = f.end.x;
1683            f.last.y = f.end.y;
1684
1685            f.end.x = evt.pageX || evt.clientX;
1686            f.end.y = evt.pageY || evt.clientY;
1687
1688            return f;
1689        }
1690
1691        /**
1692         * Returns a finger data object by its event ID.
1693         * Each touch event has an identifier property, which is used
1694         * to track repeat touches
1695         * @param {int} id The unique id of the finger in the sequence of touch events.
1696         * @return a finger data object.
1697         * @inner
1698         */
1699        function getFingerData(id) {
1700            return fingerData[id] || null;
1701        }
1702
1703
1704        /**
1705         * Sets the maximum distance swiped in the given direction.
1706         * If the new value is lower than the current value, the max value is not changed.
1707         * @param {string}  direction The direction of the swipe
1708         * @param {int}  distance The distance of the swipe
1709         * @inner
1710         */
1711        function setMaxDistance(direction, distance) {
1712            if (direction == NONE) return;
1713            distance = Math.max(distance, getMaxDistance(direction));
1714            maximumsMap[direction].distance = distance;
1715        }
1716
1717        /**
1718         * gets the maximum distance swiped in the given direction.
1719         * @param {string}  direction The direction of the swipe
1720         * @return int  The distance of the swipe
1721         * @inner
1722         */
1723        function getMaxDistance(direction) {
1724            if (maximumsMap[direction]) return maximumsMap[direction].distance;
1725            return undefined;
1726        }
1727
1728        /**
1729         * Creats a map of directions to maximum swiped values.
1730         * @return Object A dictionary of maximum values, indexed by direction.
1731         * @inner
1732         */
1733        function createMaximumsData() {
1734            var maxData = {};
1735            maxData[LEFT] = createMaximumVO(LEFT);
1736            maxData[RIGHT] = createMaximumVO(RIGHT);
1737            maxData[UP] = createMaximumVO(UP);
1738            maxData[DOWN] = createMaximumVO(DOWN);
1739
1740            return maxData;
1741        }
1742
1743        /**
1744         * Creates a map maximum swiped values for a given swipe direction
1745         * @param {string} The direction that these values will be associated with
1746         * @return Object Maximum values
1747         * @inner
1748         */
1749        function createMaximumVO(dir) {
1750            return {
1751                direction: dir,
1752                distance: 0
1753            }
1754        }
1755
1756
1757        //
1758        // MATHS / UTILS
1759        //
1760
1761        /**
1762         * Calculate the duration of the swipe
1763         * @return int
1764         * @inner
1765         */
1766        function calculateDuration() {
1767            return endTime - startTime;
1768        }
1769
1770        /**
1771         * Calculate the distance between 2 touches (pinch)
1772         * @param {point} startPoint A point object containing x and y co-ordinates
1773         * @param {point} endPoint A point object containing x and y co-ordinates
1774         * @return int;
1775         * @inner
1776         */
1777        function calculateTouchesDistance(startPoint, endPoint) {
1778            var diffX = Math.abs(startPoint.x - endPoint.x);
1779            var diffY = Math.abs(startPoint.y - endPoint.y);
1780
1781            return Math.round(Math.sqrt(diffX * diffX + diffY * diffY));
1782        }
1783
1784        /**
1785         * Calculate the zoom factor between the start and end distances
1786         * @param {int} startDistance Distance (between 2 fingers) the user started pinching at
1787         * @param {int} endDistance Distance (between 2 fingers) the user ended pinching at
1788         * @return float The zoom value from 0 to 1.
1789         * @inner
1790         */
1791        function calculatePinchZoom(startDistance, endDistance) {
1792            var percent = (endDistance / startDistance) * 1;
1793            return percent.toFixed(2);
1794        }
1795
1796
1797        /**
1798         * Returns the pinch direction, either IN or OUT for the given points
1799         * @return string Either {@link $.fn.swipe.directions.IN} or {@link $.fn.swipe.directions.OUT}
1800         * @see $.fn.swipe.directions
1801         * @inner
1802         */
1803        function calculatePinchDirection() {
1804            if (pinchZoom < 1) {
1805                return OUT;
1806            } else {
1807                return IN;
1808            }
1809        }
1810
1811
1812        /**
1813         * Calculate the length / distance of the swipe
1814         * @param {point} startPoint A point object containing x and y co-ordinates
1815         * @param {point} endPoint A point object containing x and y co-ordinates
1816         * @return int
1817         * @inner
1818         */
1819        function calculateDistance(startPoint, endPoint) {
1820            return Math.round(Math.sqrt(Math.pow(endPoint.x - startPoint.x, 2) + Math.pow(endPoint.y - startPoint.y, 2)));
1821        }
1822
1823        /**
1824         * Calculate the angle of the swipe
1825         * @param {point} startPoint A point object containing x and y co-ordinates
1826         * @param {point} endPoint A point object containing x and y co-ordinates
1827         * @return int
1828         * @inner
1829         */
1830        function calculateAngle(startPoint, endPoint) {
1831            var x = startPoint.x - endPoint.x;
1832            var y = endPoint.y - startPoint.y;
1833            var r = Math.atan2(y, x); //radians
1834            var angle = Math.round(r * 180 / Math.PI); //degrees
1835
1836            //ensure value is positive
1837            if (angle < 0) {
1838                angle = 360 - Math.abs(angle);
1839            }
1840
1841            return angle;
1842        }
1843
1844        /**
1845         * Calculate the direction of the swipe
1846         * This will also call calculateAngle to get the latest angle of swipe
1847         * @param {point} startPoint A point object containing x and y co-ordinates
1848         * @param {point} endPoint A point object containing x and y co-ordinates
1849         * @return string Either {@link $.fn.swipe.directions.LEFT} / {@link $.fn.swipe.directions.RIGHT} / {@link $.fn.swipe.directions.DOWN} / {@link $.fn.swipe.directions.UP}
1850         * @see $.fn.swipe.directions
1851         * @inner
1852         */
1853        function calculateDirection(startPoint, endPoint) {
1854
1855            if (comparePoints(startPoint, endPoint)) {
1856                return NONE;
1857            }
1858
1859            var angle = calculateAngle(startPoint, endPoint);
1860
1861            if ((angle <= 45) && (angle >= 0)) {
1862                return LEFT;
1863            } else if ((angle <= 360) && (angle >= 315)) {
1864                return LEFT;
1865            } else if ((angle >= 135) && (angle <= 225)) {
1866                return RIGHT;
1867            } else if ((angle > 45) && (angle < 135)) {
1868                return DOWN;
1869            } else {
1870                return UP;
1871            }
1872        }
1873
1874
1875        /**
1876         * Returns a MS time stamp of the current time
1877         * @return int
1878         * @inner
1879         */
1880        function getTimeStamp() {
1881            var now = new Date();
1882            return now.getTime();
1883        }
1884
1885
1886
1887        /**
1888         * Returns a bounds object with left, right, top and bottom properties for the element specified.
1889         * @param {DomNode} The DOM node to get the bounds for.
1890         */
1891        function getbounds(el) {
1892            el = $(el);
1893            var offset = el.offset();
1894
1895            var bounds = {
1896                left: offset.left,
1897                right: offset.left + el.outerWidth(),
1898                top: offset.top,
1899                bottom: offset.top + el.outerHeight()
1900            }
1901
1902            return bounds;
1903        }
1904
1905
1906        /**
1907         * Checks if the point object is in the bounds object.
1908         * @param {object} point A point object.
1909         * @param {int} point.x The x value of the point.
1910         * @param {int} point.y The x value of the point.
1911         * @param {object} bounds The bounds object to test
1912         * @param {int}
1912 bounds.left The leftmost value
1913         * @param {int} bounds.right The righttmost value
1914         * @param {int} bounds.top The topmost value
1915         * @param {int} bounds.bottom The bottommost value
1916         */
1917        function isInBounds(point, bounds) {
1918            return (point.x > bounds.left && point.x < bounds.right && point.y > bounds.top && point.y < bounds.bottom);
1919        };
1920
1921        /**
1922         * Checks if the two points are equal
1923         * @param {object} point A point object.
1924         * @param {object} point B point object.
1925         * @return true of the points match
1926         */
1927        function comparePoints(pointA, pointB) {
1928            return (pointA.x == pointB.x && pointA.y == pointB.y);
1929        }
1930
1931
1932    }
1933
1934
1935
1936
1937    /**
1938     * A catch all handler that is triggered for all swipe directions.
1939     * @name $.fn.swipe#swipe
1940     * @event
1941     * @default null
1942     * @param {EventObject} event The original event object
1943     * @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
1944     * @param {int} distance The distance the user swiped
1945     * @param {int} duration The duration of the swipe in milliseconds
1946     * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1947     * @param {object} fingerData The coordinates of fingers in event
1948     * @param {string} currentDirection The current direction the user is swiping.
1949     */
1950
1951
1952
1953
1954    /**
1955     * A handler that is triggered for "left" swipes.
1956     * @name $.fn.swipe#swipeLeft
1957     * @event
1958     * @default null
1959     * @param {EventObject} event The original event object
1960     * @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
1961     * @param {int} distance The distance the user swiped
1962     * @param {int} duration The duration of the swipe in milliseconds
1963     * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1964     * @param {object} fingerData The coordinates of fingers in event
1965     * @param {string} currentDirection The current direction the user is swiping.
1966     */
1967
1968    /**
1969     * A handler that is triggered for "right" swipes.
1970     * @name $.fn.swipe#swipeRight
1971     * @event
1972     * @default null
1973     * @param {EventObject} event The original event object
1974     * @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
1975     * @param {int} distance The distance the user swiped
1976     * @param {int} duration The duration of the swipe in milliseconds
1977     * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1978     * @param {object} fingerData The coordinates of fingers in event
1979     * @param {string} currentDirection The current direction the user is swiping.
1980     */
1981
1982    /**
1983     * A handler that is triggered for "up" swipes.
1984     * @name $.fn.swipe#swipeUp
1985     * @event
1986     * @default null
1987     * @param {EventObject} event The original event object
1988     * @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
1989     * @param {int} distance The distance the user swiped
1990     * @param {int} duration The duration of the swipe in milliseconds
1991     * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1992     * @param {object} fingerData The coordinates of fingers in event
1993     * @param {string} currentDirection The current direction the user is swiping.
1994     */
1995
1996    /**
1997     * A handler that is triggered for "down" swipes.
1998     * @name $.fn.swipe#swipeDown
1999     * @event
2000     * @default null
2001     * @param {EventObject} event The original event object
2002     * @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
2003     * @param {int} distance The distance the user swiped
2004     * @param {int} duration The duration of the swipe in milliseconds
2005     * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
2006     * @param {object} fingerData The coordinates of fingers in event
2007     * @param {string} currentDirection The current direction the user is swiping.
2008     */
2009
2010    /**
2011     * A handler triggered for every phase of the swipe. This handler is constantly f
2011ired for the duration of the pinch.
2012     * This is triggered regardless of swipe thresholds.
2013     * @name $.fn.swipe#swipeStatus
2014     * @event
2015     * @default null
2016     * @param {EventObject} event The original event object
2017     * @param {string} phase The phase of the swipe event. See {@link $.fn.swipe.phases}
2018     * @param {string} direction The direction the user swiped in. This is null if the user has yet to move. See {@link $.fn.swipe.directions}
2019     * @param {int} distance The distance the user swiped. This is 0 if the user has yet to move.
2020     * @param {int} duration The duration of the swipe in milliseconds
2021     * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
2022     * @param {object} fingerData The coordinates of fingers in event
2023     * @param {string} currentDirection The current direction the user is swiping.
2024     */
2025
2026    /**
2027     * A handler triggered for pinch in events.
2028     * @name $.fn.swipe#pinchIn
2029     * @event
2030     * @default null
2031     * @param {EventObject} event The original event object
2032     * @param {int} direction The direction the user pinched in. See {@link $.fn.swipe.directions}
2033     * @param {int} distance The distance the user pinched
2034     * @param {int} duration The duration of the swipe in milliseconds
2035     * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
2036     * @param {int} zoom The zoom/scale level the user pinched too, 0-1.
2037     * @param {object} fingerData The coordinates of fingers in event
2038     */
2039
2040    /**
2041     * A handler triggered for pinch out events.
2042     * @name $.fn.swipe#pinchOut
2043     * @event
2044     * @default null
2045     * @param {EventObject} event The original event object
2046     * @param {int} direction The direction the user pinched in. See {@link $.fn.swipe.directions}
2047     * @param {int} distance The distance the user pinched
2048     * @param {int} duration The duration of the swipe in milliseconds
2049     * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
2050     * @param {int} zoom The zoom/scale level the user pinched too, 0-1.
2051     * @param {object} fingerData The coordinates of fingers in event
2052     */
2053
2054    /**
2055     * A handler triggered for all pinch events. This handler is constantly fired for the duration of the pinch. This is triggered regardless of thresholds.
2056     * @name $.fn.swipe#pinchStatus
2057     * @event
2058     * @default null
2059     * @param {EventObject} event The original event object
2060     * @param {int} direction The direction the user pinched in. See {@link $.fn.swipe.directions}
2061     * @param {int} distance The distance the user pinched
2062     * @param {int} duration The duration of the swipe in milliseconds
2063     * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
2064     * @param {int} zoom The zoom/scale level the user pinched too, 0-1.
2065     * @param {object} fingerData The coordinates of fingers in event
2066     */
2067
2068    /**
2069     * A click handler triggered when a user simply clicks, rather than swipes on an element.
2070     * This is deprecated since version 1.6.2, any assignment to click will be assigned to the tap handler.
2071     * You cannot use <code>on</code> to bind to this event as the default jQ <code>click</code> event will be triggered.
2072     * Use the <code>tap</code> event instead.
2073     * @name $.fn.swipe#click
2074     * @event
2075     * @deprecated since version 1.6.2, please use {@link $.fn.swipe#tap} instead
2076     * @default null
2077     * @param {EventObject} event The original event object
2078     * @param {DomObject} target The element clicked on.
2079     */
2080
2081    /**
2082     * A click / tap handler triggered when a user simply clicks or taps, rather than swipes on an element.
2083     * @name $.fn.swipe#tap
2084     * @event
2085     * @default null
2086     * @param {EventObject} event The original event object
2087     * @param {DomObject} target The element clicked on.
2088     */
2089
2090    /**
2091     * A double tap handler triggered when a user double clicks or taps on an element.
2092     * You can set the time delay for a double tap with the {@link $.fn.swipe.defaults#doubleTapThreshold} property.
2093     * 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>
2094     * as the script needs to check if its a double tap.
2095     * @name $.fn.swipe#doubleTap
2096     * @see  $.fn.swipe.defaults#doubleTapThreshold
2097     * @event
2098     * @default null
2099     * @param {EventObject} event The original event object
2100     * @param {DomObject} target The element clicked on.
2101     */
2102
2103    /**
2104     * A long tap handler triggered once a tap has been release if the tap was longer than the longTapThreshold.
2105     * You can set the time delay for a long tap with the {@link $.fn.swipe.defaults#longTapThreshold} property.
2106     * @name $.fn.swipe#longTap
2107     * @see  $.fn.swipe.defaults#longTapThreshold
2108     * @event
2109     * @default null
2110     * @param {EventObject} event The original event object
2111     * @param {DomObject} target The element clicked on.
2112     */
2113
2114    /**
2115     * A hold tap handler triggered as soon as the longTapThreshold is reached
2116     * You can set the time delay for a long tap with the {@link $.fn.swipe.defaults#longTapThreshold} property.
2117     * @name $.fn.swipe#hold
2118     * @see  $.fn.swipe.defaults#longTapThreshold
2119     * @event
2120     * @default null
2121     * @param {EventObject} event The original event object
2122     * @param {DomObject} target The element clicked on.
2123     */
2124
2125}));
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145String.prototype.replaceAll = function (target, replacement) {
2146    return this.split(target).join(replacement);
2147};
2148
2149
2150
2151
2152
2153
2154
2155if (settings_ankerpunkte) {
2156    jQuery(document).ready(function () {
2157        /* zum Inhalt scrollen */
2158        if (window.location.href.indexOf("#") == -1) {
2159            var target = jQuery('#main');
2160            if (!(jQuery('body').hasClass('page-home')) && target.length) {
2161                if (!getQueryStringParameter || getQueryStringParameter('filter') == null) {
2162                    jQuery('html, body').delay(10).animate({
2163                        scrollTop: target.offset().top -100
2164                    }, 1000);
2165                    return false;
2166                };
2167            };
2168        };
2169    });
2170};
2171
2172var getQueryStringParameter = function (token) {
2173    var params = new URLSearchParams(location.search);
2174    var value = params.get(token);
2175    if (value == null) return null;
2176    return decodeURIComponent(value);
2177};
2178
2179var setQueryStringParameter = function (token, value) {
2180    const regExp = new RegExp(param + "(.+?)(&|$)", "g");
2181    const newUrl = window.location.href.replace(regExp, param + "=" + value + "$2");
2182    window.history.pushState('', '', newUrl);
2183};
2184
2185var encodeQueryData = function (data) {
2186    const ret = [];
2187    for (let d in data)
2188        ret.push(encodeURIComponent(d) + '=' + encodeURIComponent(data[d]));
2189    return ret.join('&');
2190}
2191
2192jQuery(document).ready(function () {
2193    setQueryStringParameter = function (token, value) {
2194        var params = new URLSearchParams(location.search);
2195        params.set(token, encodeURIComponent(value));
2196        if (value == null) {
2197            if (params.delete) params.delete(token);
2198            else token = '';
2199        };
2200
2201        var ps = params.toString();
2202        if (ps == '') window.history.replaceState({}, "", location.pathname);
2203        else window.history.replaceState({}, "", location.pathname + '?' + ps);
2204    };
2205});
2206
2207jQuery(document).ready(function () {
2208    jQuery('[name="Suche"]').attr({
2209        'name': 'keywords',
2210        'placeholder': 'Suche'
2211    });
2212});
2213
2214jQuery(document).ready(function () {
2215
2216    if (jQuery('select#select_adress').length) {
2217
2218        jQuery('select#select_adress').find('option').each(function (idx, elem) {
2219            if (elem && elem.value) {
2220                if (elem.value.trim() == ',') elem.remove();
2221            };
2222        });
2223
2224    };
2225});
2226
2227/* Script für Slider text */
2228
2229jQuery(document).ready(function () {
2230    jQuery('div[id^=place]').each(function (idx, elem) {
2231        var id = jQuery(elem).attr('id');
2232        jQuery('.slider-text[place="' + id + '"]').append(elem);
2233    });
2234});
2235
2236/* Script für select language function */
2237
2238jQuery(document).ready(function () {
2239    jQuery('.mod_changelanguage').find('select').bind({
2240        'change keyup': function (evt) {
2241            location.href = (jQuery(this).val());
2242        }
2243    })
2244});
2245
2246jQuery(document).ready(function () {
2247    /* Link remove */
2248    /*jQuery('a[title="Leistungen"]').on('click', function(e) {
2249      e.preventDefault();
2250    });*/
2251    jQuery(document).ready(function () {
2252        $('.carosel-control-right').click(function () {
2253            $(this).blur();
2254            $(this).parent().find('.carosel-item').first().insertAfter($(this).parent().find('.carosel-item').last());
2255            $(this).parent().find('.carosel-item').removeClass('active-effect');
2256            var that = this;
2257            setTimeout(function () {
2258                $(that).parent().find('.carosel-item').addClass('active-effect');
2259            }, 100);
2260            // $(this).parent().find('.carosel-item').first().addClass( 'active-effect' );
2261            // $(this).parent().find('.carosel-item :visible').last().addClass( 'active-effect' );
2262        });
2263        $('.carosel-control-left').click(function () {
2264            $(this).blur();
2265            $(this).parent().find('.carosel-item').last().insertBefore($(this).parent().find('.carosel-item').first());
2266            $(this).parent().find('.carosel-item').removeClass('active-effect');
2267            var that = this;
2268            setTimeout(function () {
2269                $(that).parent().find('.carosel-item').addClass('active-effect');
2270            }, 100);
2271            // $(this).parent().find('.carosel-item').first().addClass( 'active-effect' );
2272            // $(this).parent().find('.carosel-item :visible').last().addClass( 'active-effect' );
2273        });
2274    });
2275
2276    /* Sticky Header */
2277    if (jQuery('#first-navi').length) {
2278        var topnav = jQuery('#first-navi').offset().top;
2279        jQuery(window).scroll(function () {
2280            var scrollpos = jQuery(this).scrollTop();
2281            if (scrollpos >= topnav) {
2282                jQuery('#first-navi').addClass('fix');
2283            }
2284            if (scrollpos < topnav) {
2285                jQuery('#first-navi').removeClass('fix');
2286            }
2287        });
2288    }
2289
2290    jQuery("#quick-one").click(function () {
2291        jQuery("#quick-one").toggleClass("active");
2292        jQuery("#quick-two").removeClass("active");
2293        jQuery("#quick-three").removeClass("active");
2294    });
2295
2296    jQuery("#quick-two").click(function () {
2297        jQuery("#quick-one").removeClass("active");
2298        jQuery("#quick-two").toggleClass("active");
2299        jQuery("#quick-three").removeClass("active");
2300    });
2301
2302    jQuery("#quick-three").click(function () {
2303        jQuery("#quick-one").removeClass("active");
2304        jQuery("#quick-two").removeClass("active");
2305        jQuery("#quick-three").toggleClass("active");
2306    });
2307
2308    /* Modalfenster für Werbeaktionen etc. */
2309    function setCookie() {
2310        var d = new Date();
2311        d.setTime(d.getTime() + (30 * 86400000)); //30 Tage
2312        document.cookie = 'aktion=gesehen;expires=' + d.toUTCString();
2313    }
2314    jQuery('.modal').click(function () {
2315        jQuery(this).css('display', 'none');
2316        setCookie();
2317    });
2318
2319
2320    jQuery(window).on('load', function () {
2321        var elements = document.getElementsByClassName('txt-rotate');
2322        for (var i = 0; i < elements.length; i++) {
2323            var toRotate = elements[i].getAttribute('data-rotate');
2324            var period = elements[i].getAttribute('data-period');
2325            if (toRotate) {
2326                new TxtRotate(elements[i], JSON.parse(toRotate), period);
2327            }
2328        }
2329        jQuery('.infobox').addClass('animate');
2330        jQuery('.infoboxen lefttLst').addClass('animate');
2331        jQuery('.infoboxen rightLst').addClass('animate');
2332    });
2333    jQuery('#sidebarCollapse').on('click', function () {
2334        // open sidebar
2335        jQuery('.collapsible_area').toggleClass('active');
2336
2337    });
2338
2339});
2340
2341
2342
2343
2344if (settings_buttonup) {
2345    jQuery(document).ready(function () {
2346        /* jQuery( '#main' ).append( '<a id="mbutton"></a>' ); */
2347
2348        if (jQuery('#mbutton').length) {
2349            var btn = jQuery('#mbutton');
2350
2351            jQuery(window).scroll(function () {
2352                if (jQuery(window).scrollTop() > 300) {
2353                    btn.addClass('show');
2354
2355                    if (typeof (window.recaptcha) == 'object') {
2356                        jQuery('#mbutton').css({
2357                            right: '10px',
2358                            bottom: '78px'
2359                        });
2360                    };
2361                } else {
2362                    btn.removeClass('show');
2363                }
2364            });
2365
2366            btn.on('click', function (e) {
2367                e.preventDefault();
2368                jQuery('html, body').animate({
2369                    scrollTop: 0
2370                }, '300');
2371            });
2372        };
2373    });
2374};
2375
2376
2377
2378if (settings_autotarget) {
2379    jQuery(document).ready(function () {
2380        jQuery('a').each(function (idx, elem) {
2381            var href = jQuery(elem).attr('href');
2382            var target = jQuery(elem).attr('target');
2383            var firstdomain = location.hostname.split('.')[location.hostname.split('.').length - 2];
2384            if (typeof (href) == 'string' && typeof (target) == 'undefined') {
2385                if (href.indexOf('http') == 0 || href.indexOf('//') == 0) { // () && href.indexOf(firstdomain) < 0
2386                    jQuery(elem).attr({
2387                        'target': '_blank'
2388                    });
2389                };
2390            };
2391        });
2392    });
2393};
2394
2395
2396var createCookie = function (name, value, days) {
2397    var expires;
2398
2399    if (days) {
2400        var date = new Date();
2401        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
2402        expires = "; expires=" + date.toGMTString();
2403    } else {
2404        expires = "";
2405    }
2406    document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + expires + "; path=/";
2407}
2408
2409var readCookie = function readCookie(name) {
2410    var nameEQ = encodeURIComponent(name) + "=";
2411    var ca = document.cookie.split(';');
2412    for (var i = 0; i < ca.length; i++) {
2413        var c = ca[i];
2414        while (c.charAt(0) === ' ')
2415            c = c.substring(1, c.length);
2416        if (c.indexOf(nameEQ) === 0)
2417            return decodeURIComponent(c.substring(nameEQ.length, c.length));
2418    }
2419    return null;
2420}
2421
2422var eraseCookie = function (name) {
2423    createCookie(name, "", -1);
2424};
2425
2426
2427
2428
2429
2430
2431
2432
2433if (settings_iframe2video) {
2434    jQuery(document).ready(function () {
2435        setTimeout(function () {
2436            jQuery('iframe').each(function (idx, elem) {
2437                if (jQuery(elem).attr('src') && jQuery(elem).attr('src').indexOf('.mp4') > -1) {
2438                    var poster = jQuery(elem).attr('poster');
2439                    if (poster) poster = ' poster="' + poster + '"';
2440                    else poster = '';
2441                    jQuery(elem).replaceWith('<video class="evideo" ' + poster + ' controls><source src="' + jQuery(elem).attr('src') + '" type="video/mp4">Ihr Browser kann dieses Video-Format nicht wiedergeben. // Your browser does not support the video tag.</video>');
2442                };
2443            });
2444
2445            setTimeout(function () {
2446                var video = document.querySelector('video');
2447                if (video) {
2448                    video.addEventListener('ended', function () {
2449                        video.load();
2450                    });
2451                    jQuery(video).attr('autoplay', false);
2452                    var e = jQuery('video')[0];
2453                    /* e.play(); */
2454                };
2455            }, 500);
2456        }, 500);
2457    });
2458};
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468if (settings_b3slider) {
2469    jQuery(document).ready(function () {
2470        var b3slider = window.b3slider = function () {
2471            var timerevt = null;
2472
2473            jQuery('button.leftLst[pid]').each(function (idx, elem) {
2474                var pid = jQuery(elem).attr('pid');
2475                var targ = jQuery('div[pid="' + pid + '"]');
2476                var btnLeft = jQuery('button[pid="' + pid + '"].leftLst');
2477                var btnRight = jQuery('button[pid="' + pid + '"].rightLst');
2478
2479                var v = targ.attr('transformX') || 0;
2480
2481                targ.attr('transformX', v);
2482
2483                var first_width = jQuery(targ.find('.item')[0]).width();
2484                var width_outer = targ.width();
2485                var width_inner = targ.find('.MultiCarousel-inner').width();
2486
2487                if (v == 0) {
2488                    btnLeft.css({
2489                        opacity: 0.5
2490                    })
2491                } else {
2492                    btnLeft.css({
2493                        opacity: 1.0
2494                    });
2495                };
2496
2497                if (width_outer >= width_inner) {
2498                    btnRight.css({
2499                        opacity: 0.5
2500                    })
2501                } else {
2502                    btnRight.css({
2503                        opacity: 1.0
2504                    });
2505                };
2506
2507
2508                targ.swipe({
2509                    swipeStatus: function (event, phase, direction, distance, duration, fingers, fingerData, currentDirection) {
2510                        switch (phase) {
2511                            case 'start':
2512                                break;
2513
2514                            case 'move':
2515                                var dist = 0;
2516                                if (direction == 'left') dist = -distance;
2517                                if (direction == 'right') dist = distance;
2518
2519                                var v = targ.attr('transformX') || 0;
2520                                v = +v;
2521
2522                                v += dist;
2523
2524                                /*
2525                                targ.find('.MultiCarousel-inner').css({
2526                                    'transform': 'translateX(-' + v + 'px)',
2527                                    'transition-duration': '300ms'
2528                                });
2529                                */
2530                                break;
2531
2532                            case 'end':
2533                                while (distance > 0) {
2534                                    if (direction == 'right' && distance >= 64) jQuery('button[pid="' + pid + '"]' + '.leftLst').mousedown();
2535                                    if (direction == 'left' && distance >= 64) jQuery('button[pid="' + pid + '"]' + '.rightLst').mousedown();
2536                                    if (direction == 'right' && distance >= 64) jQuery('button[pid="' + pid + '"]' + '.leftLst').mouseup();
2537                                    if (direction == 'left' && distance >= 64) jQuery('button[pid="' + pid + '"]' + '.rightLst').mouseup();
2538                                    distance -= 64;
2539                                };
2540                                break;
2541
2542                            default:
2543                                break;
2544                        }
2545                    }
2546                });
2547
2548            });
2549
2550            jQuery('button.leftLst[pid],button.rightLst[pid]').unbind().bind({
2551                'mousedown': function () {
2552
2553                    jQuery(this).attr('dragging', true);
2554                    clearInterval(timerevt);
2555                    var that = this;
2556
2557                    var pid = jQuery(that).attr('pid');
2558                    var btnLeft = jQuery('button[pid="' + pid + '"].leftLst');
2559                    var btnRight = jQuery('button[pid="' + pid + '"].rightLst');
2560                    var targ = jQuery('div[pid="' + pid + '"]');
2561                    var right = jQuery(this).hasClass('rightLst');
2562                    var cnt = targ.find('.item').length;
2563                    var first_width = jQuery(targ.find('.item')[0]).width();
2564                    var width = targ.find('.MultiCarousel-inner').width() - targ.width();
2565
2566                    window.that = that;
2567                    window.targ = targ;
2568
2569                    var nextstep = function () {
2570                        var v = targ.attr('transformX') || 0;
2571                        v = +v;
2572
2573                        var stepping = 50;
2574                        stepping = width / (cnt + 1);
2575                        stepping = first_width;
2576                        v += right ? stepping : -stepping;
2577                        v = Math.round(v / stepping) * stepping;
2578                        if (v < 0) v = 0;
2579                        if (v > width) v = width;
2580
2581                        targ.find('.MultiCarousel-inner').css({
2582                            'transform': 'translateX(-' + v + 'px)',
2583                            'transition-duration': '1000ms'
2584                        });
2585
2586
2587                        targ.attr('transformX', v);
2588
2589                        if (v == 0) btnLeft.css({
2590                            opacity: 0.5
2591                        });
2592                        else btnLeft.css({
2593                            opacity: 1.0
2594                        });
2595                        if (v == width) btnRight.css({
2596                            opacity: 0.5
2597                        });
2598                        else btnRight.css({
2599                            opacity: 1.0
2600                        });
2601                    };
2602
2603                    timerevt = setInterval(function () {
2604                        nextstep();
2605                    }, 500);
2606
2607                    nextstep();
2608                },
2609                'mouseup': function () {
2610
2611                    jQuery(this).attr('dragging', false);
2612                    clearInterval(timerevt);
2613                    timerevt = null;
2614                },
2615                'mousemove': function () {
2616                    if (jQuery(this).attr('dragging')) {
2617
2618                    };
2619                }
2620            });
2621        };
2622
2623
2624
2625
2626        jQuery(window).resize(function () {
2627            // ResCarouselSize();
2628            b3slider();
2629        });
2630
2631        // ResCarouselSize();
2632        b3slider();
2633
2634    });
2635};
2636
2637(function (w) {
2638
2639    w.URLSearchParams = w.URLSearchParams || function (searchString) {
2640        var self = this;
2641        self.searchString = searchString;
2642        self.get = function (name) {
2643            var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(self.searchString);
2644            if (results == null) {
2645                return null;
2646            } else {
2647                return decodeURI(results[1]) || 0;
2648            }
2649        };
2650    }
2651
2652})(window)
2653
2654if (settings_countup) {
2655    jQuery(document).ready(function () {
2656
2657        jQuery('.countup').each(function (idx, elem) {
2658            jQuery(elem).find('span').each(function (idx, elem) {
2659                elem = jQuery(elem);
2660                var style = elem.attr('style');
2661                if (style && style.indexOf('line-through') > -1) {
2662                    style = style.replaceAll('text-decoration: line-through;', '');
2663                    elem.attr('style', style);
2664                    var count_end = parseInt(jQuery(elem).text());
2665                    if (count_end > 0) {
2666                        var ele = elem,
2667                            number = 0,
2668                            step = count_end > 500 ? (count_end > 4000 ? 16 : 9) : 1,
2669                            timer = setInterval(function () {
2670                                if (ele.is(":visible")) { // { // if (ele.is(":visible"))
2671                                    if (number == count_end || number > count_end) {
2672                                        clearInterval(timer);
2673                                        ele.text(count_end);
2674                                    } else {
2675                                        ele.text(number);
2676                                    };
2677                                    number += step;
2678                                };
2679                            }, 10);
2680                    };
2681                };
2682            });
2683        });
2684
2685    });
2686};
2687
2688if (settings_autotarget) {
2689    jQuery(document).ready(function () {
2690        jQuery('a').each(function (idx, elem) {
2691
2692            var target = jQuery(elem).attr('target');
2693            var href = jQuery(elem).attr('href');
2694            if (href && !target && href.toLowerCase().indexOf('.pdf') > 0) {
2695                jQuery(elem).attr('target', '_blank');
2696            };
2697
2698        });
2699    });
2700};
2701
2702if (settings_immoautoformfill) {
2703    jQuery(document).ready(function () {
2704        if (jQuery('input[name=Objekt]').length && getQueryStringParameter('obid')) {
2705            jQuery('input[name=Objekt]').val(getQueryStringParameter('obid'));
2706            jQuery('.immo-form-objekt-autohide').removeClass('immo-form-objekt-autohide');
2707        };
2708    });
2709};
2710
2711if (settings_potrait_no_title_popup) {
2712    jQuery(document).ready(function () {
2713        jQuery('.portrait').each(function () {
2714            jQuery(this).find('img').each(function (idx, elem) {
2715                jQuery(elem).attr({
2716                    title: ''
2717                });
2718            });
2719        });
2720    });
2721};

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.