/*! jquery.finger - v0.1.6 - 2016-10-05 * https://github.com/ngryman/jquery.finger * Copyright (c) 2016 Nicolas Gryman; Licensed MIT */ (function (factory) { if (typeof define === 'function' && define.amd) define(['jquery'], factory); else if (typeof exports === 'object') factory(require('jquery')); else factory(jQuery); }(function ($) { var ua = navigator.userAgent, isChrome = /chrome/i.exec(ua), isAndroid = /android/i.exec(ua), hasTouch = 'ontouchstart' in window && !(isChrome && !isAndroid), startEvent = hasTouch ? 'touchstart' : 'mousedown', stopEvent = hasTouch ? 'touchend touchcancel' : 'mouseup mouseleave', moveEvent = hasTouch ? 'touchmove' : 'mousemove', namespace = 'finger', rootEl = $('html')[0], start = {}, move = {}, motion, safeguard, timeout, prevEl, prevTime, Finger = $.Finger = { pressDuration: 300, doubleTapInterval: 300, flickDuration: 150, motionThreshold: 5 }; function preventDefault(event) { event.preventDefault(); $.event.remove(rootEl, 'click', preventDefault); } function page(coord, event) { return (hasTouch ? event.originalEvent.touches[0] : event)['page' + coord.toUpperCase()]; } function trigger(event, evtName, remove) { var fingerEvent = $.Event(evtName, move); $.event.trigger(fingerEvent, { originalEvent: event }, event.target); if (fingerEvent.isDefaultPrevented()) { if (~evtName.indexOf('tap') && !hasTouch) $.event.add(rootEl, 'click', preventDefault); else event.preventDefault(); } if (remove) { $.event.remove(rootEl, moveEvent + '.' + namespace, moveHandler); $.event.remove(rootEl, stopEvent + '.' + namespace, stopHandler); } } function startHandler(event) { if (event.which > 1) return; var timeStamp = event.timeStamp || +new Date(); if (safeguard == timeStamp) return; safeguard = timeStamp; // initializes data start.x = move.x = page('x', event); start.y = move.y = page('y', event); start.time = timeStamp; start.target = event.target; move.orientation = null; move.end = false; motion = false; timeout = setTimeout(function() { trigger(event, 'press', true); }, Finger.pressDuration); $.event.add(rootEl, moveEvent + '.' + namespace, moveHandler); $.event.add(rootEl, stopEvent + '.' + namespace, stopHandler); // global prevent default if (Finger.preventDefault) { event.preventDefault(); $.event.add(rootEl, 'click', preventDefault); } } function moveHandler(event) { // motion data move.x = page('x', event); move.y = page('y', event); move.dx = move.x - start.x; move.dy = move.y - start.y; move.adx = Math.abs(move.dx); move.ady = Math.abs(move.dy); // security motion = move.adx > Finger.motionThreshold || move.ady > Finger.motionThreshold; if (!motion) return; // moves cancel press events clearTimeout(timeout); // orientation if (!move.orientation) { if (move.adx > move.ady) { move.orientation = 'horizontal'; move.direction = move.dx > 0 ? +1 : -1; } else { move.orientation = 'vertical'; move.direction = move.dy > 0 ? +1 : -1; } } // for delegated events, the target may change over time // this ensures we notify the right target and simulates the mouseleave behavior while (event.target && event.target !== start.target) event.target = event.target.parentNode; if (event.target !== start.target) { event.target = start.target; stopHandler.call(this, $.Event(stopEvent + '.' + namespace, event)); return; } // fire drag event trigger(event, 'drag'); } function stopHandler(event) { var timeStamp = event.timeStamp || +new Date(), dt = timeStamp - start.time, evtName; // always clears press timeout clearTimeout(timeout); // tap-like events if (!motion) { // triggered only if targets match if (event.target === start.target) { var doubleTap = prevEl === event.target && timeStamp - prevTime < Finger.doubleTapInterval; evtName = doubleTap ? 'doubletap' : 'tap'; prevEl = doubleTap ? null : start.target; prevTime = timeStamp; } } // motion events else { // ensure last target is set the initial one event.target = start.target; if (dt < Finger.flickDuration) trigger(event, 'flick'); move.end = true; evtName = 'drag'; } if (evtName) trigger(event, evtName, true); } // initial binding $.event.add(rootEl, startEvent + '.' + namespace, startHandler); // expose events as methods $.each('tap doubletap press drag flick'.split(' '), function(i, name) { $.fn[name] = function(fn) { return fn ? this.on(name, fn) : this.trigger(name); }; }); return Finger; }));