source: extensions/Versa/js/jquery.mobile-events.js @ 31977

Last change on this file since 31977 was 31833, checked in by lexming, 7 years ago

Initial commit

File size: 39.1 KB
Line 
1/*!
2 * jQuery Mobile Events
3 * by Ben Major
4 *
5 * Copyright 2011-2017, Ben Major
6 * Licensed under the MIT License:
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 *
26 */
27
28"use strict";
29
30(function ($) {
31    $.attrFn = $.attrFn || {};
32
33    // navigator.userAgent.toLowerCase() isn't reliable for Chrome installs
34    // on mobile devices. As such, we will create a boolean isChromeDesktop
35    // The reason that we need to do this is because Chrome annoyingly
36    // purports support for touch events even if the underlying hardware
37    // does not!
38    var touchCapable = ('ontouchstart' in window),
39       
40        settings = {
41            tap_pixel_range: 5,
42            swipe_h_threshold: 50,
43            swipe_v_threshold: 50,
44            taphold_threshold: 750,
45            doubletap_int: 500,
46
47            touch_capable: touchCapable,
48            orientation_support: ('orientation' in window && 'onorientationchange' in window),
49
50            startevent:  (touchCapable) ? 'touchstart' : 'mousedown',
51            endevent:    (touchCapable) ? 'touchend' : 'mouseup',
52            moveevent:   (touchCapable) ? 'touchmove' : 'mousemove',
53            tapevent:    (touchCapable) ? 'tap' : 'click',
54            scrollevent: (touchCapable) ? 'touchmove' : 'scroll',
55
56            hold_timer: null,
57            tap_timer: null
58        };
59   
60    // Convenience functions:
61    $.isTouchCapable = function() { return settings.touch_capable; };
62    $.getStartEvent  = function() { return settings.startevent;    };
63    $.getEndEvent    = function() { return settings.endevent;      };
64    $.getMoveEvent   = function() { return settings.moveevent;     };
65    $.getTapEvent    = function() { return settings.tapevent;      };
66    $.getScrollEvent = function() { return settings.scrollevent;   };
67   
68    // Add Event shortcuts:
69    $.each(['tapstart', 'tapend', 'tapmove', 'tap', 'tap2', 'tap3', 'tap4', 'singletap', 'doubletap', 'taphold', 'swipe', 'swipeup', 'swiperight', 'swipedown', 'swipeleft', 'swipeend', 'scrollstart', 'scrollend', 'orientationchange'], function (i, name) {
70        $.fn[name] = function (fn) {
71            return fn ? this.on(name, fn) : this.trigger(name);
72        };
73
74        $.attrFn[name] = true;
75    });
76
77    // tapstart Event:
78    $.event.special.tapstart = {
79        setup: function () {
80                       
81            var thisObject = this,
82                $this = $(thisObject);
83                       
84            $this.on(settings.startevent, function tapStartFunc(e) {
85                               
86                $this.data('callee', tapStartFunc);
87                if (e.which && e.which !== 1) {
88                    return false;
89                }
90
91                var origEvent = e.originalEvent,
92                    touchData = {
93                        'position': {
94                            'x': ((settings.touch_capable) ? origEvent.touches[0].pageX : e.pageX),
95                            'y': (settings.touch_capable) ? origEvent.touches[0].pageY : e.pageY
96                        },
97                        'offset': {
98                            'x': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageX - ($this.offset() ? $this.offset().left : 0)) : Math.round(e.pageX - ($this.offset() ? $this.offset().left : 0)),
99                            'y': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageY - ($this.offset() ? $this.offset().top : 0)) : Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0))
100                        },
101                        'time': Date.now(),
102                        'target': e.target
103                    };
104                               
105                triggerCustomEvent(thisObject, 'tapstart', e, touchData);
106                return true;
107            });
108        },
109
110        remove: function () {
111            $(this).off(settings.startevent, $(this).data.callee);
112        }
113    };
114       
115    // tapmove Event:
116    $.event.special.tapmove = {
117        setup: function() {
118            var thisObject = this,
119            $this = $(thisObject);
120                       
121            $this.on(settings.moveevent, function tapMoveFunc(e) {
122                $this.data('callee', tapMoveFunc);
123                       
124                var origEvent = e.originalEvent,
125                    touchData = {
126                        'position': {
127                            'x': ((settings.touch_capable) ? origEvent.touches[0].pageX : e.pageX),
128                            'y': (settings.touch_capable) ? origEvent.touches[0].pageY : e.pageY
129                        },
130                        'offset': {
131                            'x': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageX - ($this.offset() ? $this.offset().left : 0)) : Math.round(e.pageX - ($this.offset() ? $this.offset().left : 0)),
132                                                        'y': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageY - ($this.offset() ? $this.offset().top : 0)) : Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0))
133                        },
134                        'time': Date.now(),
135                        'target': e.target
136                    };
137                               
138                triggerCustomEvent(thisObject, 'tapmove', e, touchData);
139                return true;
140            });
141        },
142        remove: function() {
143            $(this).off(settings.moveevent, $(this).data.callee);
144        }
145    };
146
147    // tapend Event:
148    $.event.special.tapend = {
149        setup: function () {
150            var thisObject = this,
151                $this = $(thisObject);
152
153            $this.on(settings.endevent, function tapEndFunc(e) {
154                // Touch event data:
155                $this.data('callee', tapEndFunc);
156
157                var origEvent = e.originalEvent;
158                var touchData = {
159                    'position': {
160                        'x': (settings.touch_capable) ? origEvent.changedTouches[0].pageX : e.pageX,
161                        'y': (settings.touch_capable) ? origEvent.changedTouches[0].pageY : e.pageY
162                    },
163                    'offset': {
164                        'x': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageX - ($this.offset() ? $this.offset().left : 0)) : Math.round(e.pageX - ($this.offset() ? $this.offset().left : 0)),
165                        'y': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageY - ($this.offset() ? $this.offset().top : 0)) : Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0))
166                    },
167                    'time': Date.now(),
168                    'target': e.target
169                };
170                triggerCustomEvent(thisObject, 'tapend', e, touchData);
171                return true;
172            });
173        },
174        remove: function () {
175            $(this).off(settings.endevent, $(this).data.callee);
176        }
177    };
178
179    // taphold Event:
180    $.event.special.taphold = {
181        setup: function () {
182            var thisObject = this,
183                $this = $(thisObject),
184                origTarget,
185                start_pos = {
186                    x: 0,
187                    y: 0
188                },
189                end_x = 0,
190                end_y = 0;
191
192            $this.on(settings.startevent, function tapHoldFunc1(e) {
193                if (e.which && e.which !== 1) {
194                    return false;
195                } else {
196                    $this.data('tapheld', false);
197                    origTarget = e.target;
198
199                    var origEvent = e.originalEvent;
200                    var start_time = Date.now(),
201                        startPosition = {
202                            'x': (settings.touch_capable) ? origEvent.touches[0].pageX : e.pageX,
203                            'y': (settings.touch_capable) ? origEvent.touches[0].pageY : e.pageY
204                        },
205                        startOffset = {
206                            'x': (settings.touch_capable) ? origEvent.touches[0].pageX - origEvent.touches[0].target.offsetLeft : e.offsetX,
207                            'y': (settings.touch_capable) ? origEvent.touches[0].pageY - origEvent.touches[0].target.offsetTop : e.offsetY
208                        };
209
210                    start_pos.x = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageX : e.pageX;
211                    start_pos.y = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageY : e.pageY;
212
213                    end_x = start_pos.x;
214                    end_y = start_pos.y;
215                   
216                    // Get the element's threshold:
217                   
218                    var ele_threshold = ($this.parent().data('threshold')) ? $this.parent().data('threshold') : $this.data('threshold'),
219                        threshold = (typeof ele_threshold !== 'undefined' && ele_threshold !== false && parseInt(ele_threshold)) ? parseInt(ele_threshold) : settings.taphold_threshold; 
220
221                    settings.hold_timer = window.setTimeout(function () {
222
223                        var diff_x = (start_pos.x - end_x),
224                            diff_y = (start_pos.y - end_y);
225
226                        if (e.target == origTarget && ((start_pos.x == end_x && start_pos.y == end_y) || (diff_x >= -(settings.tap_pixel_range) && diff_x <= settings.tap_pixel_range && diff_y >= -(settings.tap_pixel_range) && diff_y <= settings.tap_pixel_range))) {
227                            $this.data('tapheld', true);
228
229                            var end_time = Date.now(),
230                                endPosition = {
231                                    'x': (settings.touch_capable) ? origEvent.touches[0].pageX : e.pageX,
232                                    'y': (settings.touch_capable) ? origEvent.touches[0].pageY : e.pageY
233                                },
234                                endOffset = {
235                                    'x': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageX - ($this.offset() ? $this.offset().left : 0)) : Math.round(e.pageX - ($this.offset() ? $this.offset().left : 0)),
236                                                                        'y': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageY - ($this.offset() ? $this.offset().top : 0)) : Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0))
237                                };
238                            var duration = end_time - start_time;
239
240                            // Build the touch data:
241                            var touchData = {
242                                'startTime': start_time,
243                                'endTime': end_time,
244                                'startPosition': startPosition,
245                                'startOffset': startOffset,
246                                'endPosition': endPosition,
247                                'endOffset': endOffset,
248                                'duration': duration,
249                                'target': e.target
250                            };
251                            $this.data('callee1', tapHoldFunc1);
252                            triggerCustomEvent(thisObject, 'taphold', e, touchData);
253                        }
254                    }, threshold);
255
256                    return true;
257                }
258            }).on(settings.endevent, function tapHoldFunc2() {
259                $this.data('callee2', tapHoldFunc2);
260                $this.data('tapheld', false);
261                window.clearTimeout(settings.hold_timer);
262            })
263            .on(settings.moveevent, function tapHoldFunc3(e) {
264                $this.data('callee3', tapHoldFunc3);
265                               
266                end_x = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageX : e.pageX;
267                end_y = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageY : e.pageY;
268            });
269        },
270
271        remove: function () {
272            $(this).off(settings.startevent, $(this).data.callee1).off(settings.endevent, $(this).data.callee2).off(settings.moveevent, $(this).data.callee3);
273        }
274    };
275
276    // doubletap Event:
277    $.event.special.doubletap = {
278        setup: function () {
279            var thisObject = this,
280                $this = $(thisObject),
281                origTarget,
282                action,
283                firstTap = null,
284                origEvent,
285                                cooloff,
286                                cooling = false;
287
288            $this.on(settings.startevent, function doubleTapFunc1(e) {
289                if (e.which && e.which !== 1) {
290                    return false;
291                }
292                $this.data('doubletapped', false);
293                origTarget = e.target;
294                $this.data('callee1', doubleTapFunc1);
295
296                origEvent = e.originalEvent;
297                if (!firstTap) {
298                    firstTap = {
299                        'position': {
300                            'x': (settings.touch_capable) ? origEvent.touches[0].pageX : e.pageX,
301                            'y': (settings.touch_capable) ? origEvent.touches[0].pageY : e.pageY
302                        },
303                        'offset': {
304                            'x': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageX - ($this.offset() ? $this.offset().left : 0)) : Math.round(e.pageX - ($this.offset() ? $this.offset().left : 0)),
305                            'y': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageY - ($this.offset() ? $this.offset().top : 0)) : Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0))
306                        },
307                        'time': Date.now(),
308                        'target': e.target
309                    };
310                }
311
312                return true;
313            }).on(settings.endevent, function doubleTapFunc2(e) {
314                               
315                var now = Date.now();
316                var lastTouch = $this.data('lastTouch') || now + 1;
317                var delta = now - lastTouch;
318                window.clearTimeout(action);
319                $this.data('callee2', doubleTapFunc2);
320
321                if (delta < settings.doubletap_int && (e.target == origTarget) && delta > 100) {
322                    $this.data('doubletapped', true);
323                    window.clearTimeout(settings.tap_timer);
324
325                    // Now get the current event:
326                    var lastTap = {
327                        'position': {
328                            'x': (settings.touch_capable) ? e.originalEvent.changedTouches[0].pageX : e.pageX,
329                            'y': (settings.touch_capable) ? e.originalEvent.changedTouches[0].pageY : e.pageY
330                        },
331                        'offset': {
332                            'x': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageX - ($this.offset() ? $this.offset().left : 0)) : Math.round(e.pageX - ($this.offset() ? $this.offset().left : 0)),
333                            'y': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageY - ($this.offset() ? $this.offset().top : 0)) : Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0))
334                        },
335                        'time': Date.now(),
336                        'target': e.target
337                    };
338
339                    var touchData = {
340                        'firstTap': firstTap,
341                        'secondTap': lastTap,
342                        'interval': lastTap.time - firstTap.time
343                    };
344
345                    if (!cooling) {
346                        triggerCustomEvent(thisObject, 'doubletap', e, touchData);
347                        firstTap = null;
348                    }
349                   
350                    cooling = true;
351                   
352                    cooloff = window.setTimeout(function () {
353                        cooling = false;
354                    }, settings.doubletap_int);
355                                       
356                } else {
357                    $this.data('lastTouch', now);
358                    action = window.setTimeout(function () {
359                        firstTap = null;
360                        window.clearTimeout(action);
361                    }, settings.doubletap_int, [e]);
362                }
363                $this.data('lastTouch', now);
364            });
365        },
366        remove: function () {
367            $(this).off(settings.startevent, $(this).data.callee1).off(settings.endevent, $(this).data.callee2);
368        }
369    };
370
371    // singletap Event:
372    // This is used in conjuction with doubletap when both events are needed on the same element
373    $.event.special.singletap = {
374        setup: function () {
375            var thisObject = this,
376                $this = $(thisObject),
377                origTarget = null,
378                startTime = null,
379                start_pos = {
380                    x: 0,
381                    y: 0
382                };
383
384            $this.on(settings.startevent, function singleTapFunc1(e) {
385                if (e.which && e.which !== 1) {
386                    return false;
387                } else {
388                    startTime = Date.now();
389                    origTarget = e.target;
390                    $this.data('callee1', singleTapFunc1);
391
392                    // Get the start x and y position:
393                    start_pos.x = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageX : e.pageX;
394                    start_pos.y = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageY : e.pageY;
395                   
396                    return true;
397                }
398            }).on(settings.endevent, function singleTapFunc2(e) {
399                $this.data('callee2', singleTapFunc2);
400                if (e.target == origTarget) {
401                   
402                    // Get the end point:
403                    var end_pos_x = (e.originalEvent.changedTouches) ? e.originalEvent.changedTouches[0].pageX : e.pageX,
404                        end_pos_y = (e.originalEvent.changedTouches) ? e.originalEvent.changedTouches[0].pageY : e.pageY;
405                   
406                    // We need to check if it was a taphold:
407
408                    settings.tap_timer = window.setTimeout(function () {
409                       
410                        var diff_x = (start_pos.x - end_pos_x), diff_y = (start_pos.y - end_pos_y);
411                       
412                        if(!$this.data('doubletapped') && !$this.data('tapheld') && (((start_pos.x == end_pos_x) && (start_pos.y == end_pos_y)) || (diff_x >= -(settings.tap_pixel_range) && diff_x <= settings.tap_pixel_range && diff_y >= -(settings.tap_pixel_range) && diff_y <= settings.tap_pixel_range))) {
413
414                            var origEvent = e.originalEvent;
415                            var touchData = {
416                                'position': {
417                                    'x': (settings.touch_capable) ? origEvent.changedTouches[0].pageX : e.pageX,
418                                    'y': (settings.touch_capable) ? origEvent.changedTouches[0].pageY : e.pageY
419                                },
420                                'offset': {
421                                    'x': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageX - ($this.offset() ? $this.offset().left : 0)) : Math.round(e.pageX - ($this.offset() ? $this.offset().left : 0)),
422                                                                        'y': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageY - ($this.offset() ? $this.offset().top : 0)) : Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0))
423                                },
424                                'time': Date.now(),
425                                'target': e.target
426                            };
427                           
428                            // Was it a taphold?
429                            if((touchData.time - startTime) < settings.taphold_threshold)
430                            {
431                                triggerCustomEvent(thisObject, 'singletap', e, touchData);
432                            }
433                        }
434                    }, settings.doubletap_int);
435                }
436            });
437        },
438
439        remove: function () {
440            $(this).off(settings.startevent, $(this).data.callee1).off(settings.endevent, $(this).data.callee2);
441        }
442    };
443
444    // tap Event:
445    $.event.special.tap = {
446        setup: function () {
447            var thisObject = this,
448                $this = $(thisObject),
449                started = false,
450                origTarget = null,
451                start_time,
452                start_pos = {
453                    x: 0,
454                    y: 0
455                },
456                touches;
457
458            $this.on(settings.startevent, function tapFunc1(e) {
459                $this.data('callee1', tapFunc1);
460
461                if( e.which && e.which !== 1 )
462                                {
463                    return false;
464                }
465                                else
466                                {
467                    started = true;
468                    start_pos.x = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageX : e.pageX;
469                    start_pos.y = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageY : e.pageY;
470                    start_time = Date.now();
471                    origTarget = e.target;
472                                       
473                    touches = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches : [ e ];
474                    return true;
475                }
476            }).on(settings.endevent, function tapFunc2(e) {
477                $this.data('callee2', tapFunc2);
478
479                // Only trigger if they've started, and the target matches:
480                var end_x = (e.originalEvent.targetTouches) ? e.originalEvent.changedTouches[0].pageX : e.pageX,
481                    end_y = (e.originalEvent.targetTouches) ? e.originalEvent.changedTouches[0].pageY : e.pageY,
482                    diff_x = (start_pos.x - end_x),
483                    diff_y = (start_pos.y - end_y),
484                    eventName;
485                                       
486                if (origTarget == e.target && started && ((Date.now() - start_time) < settings.taphold_threshold) && ((start_pos.x == end_x && start_pos.y == end_y) || (diff_x >= -(settings.tap_pixel_range) && diff_x <= settings.tap_pixel_range && diff_y >= -(settings.tap_pixel_range) && diff_y <= settings.tap_pixel_range))) {
487                    var origEvent = e.originalEvent;
488                    var touchData = [ ];
489                                       
490                    for( var i = 0; i < touches.length; i++)
491                    {
492                        var touch = {
493                            'position': {
494                                'x': (settings.touch_capable) ? origEvent.changedTouches[i].pageX : e.pageX,
495                                'y': (settings.touch_capable) ? origEvent.changedTouches[i].pageY : e.pageY
496                            },
497                            'offset': {
498                                'x': (settings.touch_capable) ? Math.round(origEvent.changedTouches[i].pageX - ($this.offset() ? $this.offset().left : 0)) : Math.round(e.pageX - ($this.offset() ? $this.offset().left : 0)),
499                                'y': (settings.touch_capable) ? Math.round(origEvent.changedTouches[i].pageY - ($this.offset() ? $this.offset().top : 0)) : Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0))
500                            },
501                            'time': Date.now(),
502                            'target': e.target
503                        };
504                       
505                        touchData.push( touch );
506                    }
507                   
508                    triggerCustomEvent(thisObject, 'tap', e, touchData);
509                }
510            });
511        },
512
513        remove: function () {
514            $(this).off(settings.startevent, $(this).data.callee1).off(settings.endevent, $(this).data.callee2);
515        }
516    };
517
518    // swipe Event (also handles swipeup, swiperight, swipedown and swipeleft):
519    $.event.special.swipe = {
520        setup: function () {
521            var thisObject = this,
522                $this = $(thisObject),
523                started = false,
524                hasSwiped = false,
525                originalCoord = {
526                    x: 0,
527                    y: 0
528                },
529                finalCoord = {
530                    x: 0,
531                    y: 0
532                },
533                startEvnt;
534
535            // Screen touched, store the original coordinate
536
537            function touchStart(e) {
538                $this = $(e.currentTarget);
539                $this.data('callee1', touchStart);
540                originalCoord.x = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageX : e.pageX;
541                originalCoord.y = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageY : e.pageY;
542                finalCoord.x = originalCoord.x;
543                finalCoord.y = originalCoord.y;
544                started = true;
545                var origEvent = e.originalEvent;
546                // Read event data into our startEvt:
547                startEvnt = {
548                    'position': {
549                        'x': (settings.touch_capable) ? origEvent.touches[0].pageX : e.pageX,
550                        'y': (settings.touch_capable) ? origEvent.touches[0].pageY : e.pageY
551                    },
552                    'offset': {
553                        'x': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageX - ($this.offset() ? $this.offset().left : 0)) : Math.round(e.pageX - ($this.offset() ? $this.offset().left : 0)),
554                        'y': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageY - ($this.offset() ? $this.offset().top : 0)) : Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0))
555                    },
556                    'time': Date.now(),
557                    'target': e.target
558                };
559            }
560
561            // Store coordinates as finger is swiping
562
563            function touchMove(e) {
564                $this = $(e.currentTarget);
565                $this.data('callee2', touchMove);
566                finalCoord.x = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageX : e.pageX;
567                finalCoord.y = (e.originalEvent.targetTouches) ? e.originalEvent.targetTouches[0].pageY : e.pageY;
568
569                var swipedir;
570
571                // We need to check if the element to which the event was bound contains a data-xthreshold | data-vthreshold:
572                var ele_x_threshold = ($this.parent().data('xthreshold')) ? $this.parent().data('xthreshold') : $this.data('xthreshold'),
573                    ele_y_threshold = ($this.parent().data('ythreshold')) ? $this.parent().data('ythreshold') : $this.data('ythreshold'),
574                    h_threshold = (typeof ele_x_threshold !== 'undefined' && ele_x_threshold !== false && parseInt(ele_x_threshold)) ? parseInt(ele_x_threshold) : settings.swipe_h_threshold,
575                    v_threshold = (typeof ele_y_threshold !== 'undefined' && ele_y_threshold !== false && parseInt(ele_y_threshold)) ? parseInt(ele_y_threshold) : settings.swipe_v_threshold; 
576               
577                if (originalCoord.y > finalCoord.y && (originalCoord.y - finalCoord.y > v_threshold)) {
578                    swipedir = 'swipeup';
579                }
580                if (originalCoord.x < finalCoord.x && (finalCoord.x - originalCoord.x > h_threshold)) {
581                    swipedir = 'swiperight';
582                }
583                if (originalCoord.y < finalCoord.y && (finalCoord.y - originalCoord.y > v_threshold)) {
584                    swipedir = 'swipedown';
585                }
586                if (originalCoord.x > finalCoord.x && (originalCoord.x - finalCoord.x > h_threshold)) {
587                    swipedir = 'swipeleft';
588                }
589                if (swipedir != undefined && started) {
590                    originalCoord.x = 0;
591                    originalCoord.y = 0;
592                    finalCoord.x = 0;
593                    finalCoord.y = 0;
594                    started = false;
595
596                    // Read event data into our endEvnt:
597                    var origEvent = e.originalEvent;
598                    var endEvnt = {
599                        'position': {
600                            'x': (settings.touch_capable) ? origEvent.touches[0].pageX : e.pageX,
601                            'y': (settings.touch_capable) ? origEvent.touches[0].pageY : e.pageY
602                        },
603                        'offset': {
604                            'x': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageX - ($this.offset() ? $this.offset().left : 0)) : Math.round(e.pageX - ($this.offset() ? $this.offset().left : 0)),
605                            'y': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageY - ($this.offset() ? $this.offset().top : 0)) : Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0))
606                        },
607                        'time': Date.now(),
608                        'target': e.target
609                    };
610
611                    // Calculate the swipe amount (normalized):
612                    var xAmount = Math.abs(startEvnt.position.x - endEvnt.position.x),
613                        yAmount = Math.abs(startEvnt.position.y - endEvnt.position.y);
614
615                    var touchData = {
616                        'startEvnt': startEvnt,
617                        'endEvnt': endEvnt,
618                        'direction': swipedir.replace('swipe', ''),
619                        'xAmount': xAmount,
620                        'yAmount': yAmount,
621                        'duration': endEvnt.time - startEvnt.time
622                    };
623                    hasSwiped = true;
624                    $this.trigger('swipe', touchData).trigger(swipedir, touchData);
625                }
626            }
627
628            function touchEnd(e) {
629                $this = $(e.currentTarget);
630                var swipedir = "";
631                $this.data('callee3', touchEnd);
632                if (hasSwiped) {
633                    // We need to check if the element to which the event was bound contains a data-xthreshold | data-vthreshold:
634                    var ele_x_threshold = $this.data('xthreshold'),
635                        ele_y_threshold = $this.data('ythreshold'),
636                        h_threshold = (typeof ele_x_threshold !== 'undefined' && ele_x_threshold !== false && parseInt(ele_x_threshold)) ? parseInt(ele_x_threshold) : settings.swipe_h_threshold,
637                        v_threshold = (typeof ele_y_threshold !== 'undefined' && ele_y_threshold !== false && parseInt(ele_y_threshold)) ? parseInt(ele_y_threshold) : settings.swipe_v_threshold;
638
639                    var origEvent = e.originalEvent;
640                    var endEvnt = {
641                        'position': {
642                            'x': (settings.touch_capable) ? origEvent.changedTouches[0].pageX : e.pageX,
643                            'y': (settings.touch_capable) ? origEvent.changedTouches[0].pageY : e.pageY
644                        },
645                        'offset': {
646                            'x': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageX - ($this.offset() ? $this.offset().left : 0)) : Math.round(e.pageX - ($this.offset() ? $this.offset().left : 0)),
647                            'y': (settings.touch_capable) ? Math.round(origEvent.changedTouches[0].pageY - ($this.offset() ? $this.offset().top : 0)) : Math.round(e.pageY - ($this.offset() ? $this.offset().top : 0))
648                        },
649                        'time': Date.now(),
650                        'target': e.target
651                    };
652
653                    // Read event data into our endEvnt:
654                    if (startEvnt.position.y > endEvnt.position.y && (startEvnt.position.y - endEvnt.position.y > v_threshold)) {
655                        swipedir = 'swipeup';
656                    }
657                    if (startEvnt.position.x < endEvnt.position.x && (endEvnt.position.x - startEvnt.position.x > h_threshold)) {
658                        swipedir = 'swiperight';
659                    }
660                    if (startEvnt.position.y < endEvnt.position.y && (endEvnt.position.y - startEvnt.position.y > v_threshold)) {
661                        swipedir = 'swipedown';
662                    }
663                    if (startEvnt.position.x > endEvnt.position.x && (startEvnt.position.x - endEvnt.position.x > h_threshold)) {
664                        swipedir = 'swipeleft';
665                    }
666
667                    // Calculate the swipe amount (normalized):
668                    var xAmount = Math.abs(startEvnt.position.x - endEvnt.position.x),
669                        yAmount = Math.abs(startEvnt.position.y - endEvnt.position.y);
670
671                    var touchData = {
672                        'startEvnt': startEvnt,
673                        'endEvnt': endEvnt,
674                        'direction': swipedir.replace('swipe', ''),
675                        'xAmount': xAmount,
676                        'yAmount': yAmount,
677                        'duration': endEvnt.time - startEvnt.time
678                    };
679                    $this.trigger('swipeend', touchData);
680                }
681
682                started = false;
683                hasSwiped = false;
684            }
685
686            $this.on(settings.startevent, touchStart);
687            $this.on(settings.moveevent, touchMove);
688            $this.on(settings.endevent, touchEnd);
689        },
690
691        remove: function () {
692            $(this).off(settings.startevent, $(this).data.callee1).off(settings.moveevent, $(this).data.callee2).off(settings.endevent, $(this).data.callee3);
693        }
694    };
695
696    // scrollstart Event (also handles scrollend):
697    $.event.special.scrollstart = {
698        setup: function () {
699            var thisObject = this,
700                $this = $(thisObject),
701                scrolling,
702                timer;
703
704            function trigger(event, state) {
705                scrolling = state;
706                triggerCustomEvent(thisObject, scrolling ? 'scrollstart' : 'scrollend', event);
707            }
708
709            // iPhone triggers scroll after a small delay; use touchmove instead
710            $this.on(settings.scrollevent, function scrollFunc(event) {
711                $this.data('callee', scrollFunc);
712
713                if (!scrolling) {
714                    trigger(event, true);
715                }
716
717                clearTimeout(timer);
718                timer = setTimeout(function () {
719                    trigger(event, false);
720                }, 50);
721            });
722        },
723
724        remove: function () {
725            $(this).off(settings.scrollevent, $(this).data.callee);
726        }
727    };
728
729    // This is the orientation change (largely borrowed from jQuery Mobile):
730    var win = $(window),
731        special_event,
732        get_orientation,
733        last_orientation,
734        initial_orientation_is_landscape,
735        initial_orientation_is_default,
736        portrait_map = {
737            '0': true,
738            '180': true
739        };
740
741    if (settings.orientation_support) {
742        var ww = window.innerWidth || win.width(),
743            wh = window.innerHeight || win.height(),
744            landscape_threshold = 50;
745
746        initial_orientation_is_landscape = ww > wh && (ww - wh) > landscape_threshold;
747        initial_orientation_is_default = portrait_map[window.orientation];
748
749        if ((initial_orientation_is_landscape && initial_orientation_is_default) || (!initial_orientation_is_landscape && !initial_orientation_is_default)) {
750            portrait_map = {
751                '-90': true,
752                '90': true
753            };
754        }
755    }
756
757    $.event.special.orientationchange = special_event = {
758        setup: function () {
759            // If the event is supported natively, return false so that jQuery
760            // will on to the event using DOM methods.
761            if (settings.orientation_support) {
762                return false;
763            }
764
765            // Get the current orientation to avoid initial double-triggering.
766            last_orientation = get_orientation();
767
768            win.on('throttledresize', handler);
769            return true;
770        },
771        teardown: function () {
772            if (settings.orientation_support) {
773                return false;
774            }
775
776            win.off('throttledresize', handler);
777            return true;
778        },
779        add: function (handleObj) {
780            // Save a reference to the bound event handler.
781            var old_handler = handleObj.handler;
782
783            handleObj.handler = function (event) {
784                event.orientation = get_orientation();
785                return old_handler.apply(this, arguments);
786            };
787        }
788    };
789
790    // If the event is not supported natively, this handler will be bound to
791    // the window resize event to simulate the orientationchange event.
792
793    function handler() {
794        // Get the current orientation.
795        var orientation = get_orientation();
796
797        if (orientation !== last_orientation) {
798            // The orientation has changed, so trigger the orientationchange event.
799            last_orientation = orientation;
800            win.trigger("orientationchange");
801        }
802    }
803
804    $.event.special.orientationchange.orientation = get_orientation = function () {
805        var isPortrait = true,
806            elem = document.documentElement;
807
808        if (settings.orientation_support) {
809            isPortrait = portrait_map[window.orientation];
810        } else {
811            isPortrait = elem && elem.clientWidth / elem.clientHeight < 1.1;
812        }
813
814        return isPortrait ? 'portrait' : 'landscape';
815    };
816
817    // throttle Handler:
818    $.event.special.throttledresize = {
819        setup: function () {
820            $(this).on('resize', throttle_handler);
821        },
822        teardown: function () {
823            $(this).off('resize', throttle_handler);
824        }
825    };
826
827    var throttle = 250,
828        throttle_handler = function () {
829            curr = Date.now();
830            diff = curr - lastCall;
831
832            if (diff >= throttle) {
833                lastCall = curr;
834                $(this).trigger('throttledresize');
835
836            } else {
837                if (heldCall) {
838                    window.clearTimeout(heldCall);
839                }
840
841                // Promise a held call will still execute
842                heldCall = window.setTimeout(handler, throttle - diff);
843            }
844        },
845        lastCall = 0,
846        heldCall,
847        curr,
848        diff;
849
850    // Trigger a custom event:
851
852    function triggerCustomEvent(obj, eventType, event, touchData) {
853        var originalType = event.type;
854        event.type = eventType;
855
856        $.event.dispatch.call(obj, event, touchData);
857        event.type = originalType;
858    }
859
860    // Correctly on anything we've overloaded:
861    $.each({
862        scrollend: 'scrollstart',
863        swipeup: 'swipe',
864        swiperight: 'swipe',
865        swipedown: 'swipe',
866        swipeleft: 'swipe',
867        swipeend: 'swipe',
868        tap2: 'tap'
869    }, function (e, srcE) {
870        $.event.special[e] = {
871            setup: function () {
872                $(this).on(srcE, $.noop);
873            }
874        };
875    });
876
877}(jQuery));
Note: See TracBrowser for help on using the repository browser.