// zepto.js // (c) 2010-2016 thomas fuchs // zepto.js may be freely distributed under the mit license. ;(function($){ var touch = {}, touchtimeout, taptimeout, swipetimeout, longtaptimeout, longtapdelay = 750, gesture function swipedirection(x1, x2, y1, y2) { return math.abs(x1 - x2) >= math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'left' : 'right') : (y1 - y2 > 0 ? 'up' : 'down') } function longtap() { longtaptimeout = null if (touch.last) { touch.el.trigger('longtap') touch = {} } } function cancellongtap() { if (longtaptimeout) cleartimeout(longtaptimeout) longtaptimeout = null } function cancelall() { if (touchtimeout) cleartimeout(touchtimeout) if (taptimeout) cleartimeout(taptimeout) if (swipetimeout) cleartimeout(swipetimeout) if (longtaptimeout) cleartimeout(longtaptimeout) touchtimeout = taptimeout = swipetimeout = longtaptimeout = null touch = {} } function isprimarytouch(event){ return (event.pointertype == 'touch' || event.pointertype == event.mspointer_type_touch) && event.isprimary } function ispointereventtype(e, type){ return (e.type == 'pointer'+type || e.type.tolowercase() == 'mspointer'+type) } $(document).ready(function(){ var now, delta, deltax = 0, deltay = 0, firsttouch, _ispointertype if ('msgesture' in window) { gesture = new msgesture() gesture.target = document.body } $(document) .bind('msgestureend', function(e){ var swipedirectionfromvelocity = e.velocityx > 1 ? 'right' : e.velocityx < -1 ? 'left' : e.velocityy > 1 ? 'down' : e.velocityy < -1 ? 'up' : null if (swipedirectionfromvelocity) { touch.el.trigger('swipe') touch.el.trigger('swipe'+ swipedirectionfromvelocity) } }) .on('touchstart mspointerdown pointerdown', function(e){ if((_ispointertype = ispointereventtype(e, 'down')) && !isprimarytouch(e)) return firsttouch = _ispointertype ? e.originalevent : e.originalevent.touches[0] if (e.originalevent.touches && e.originalevent.touches.length === 1 && touch.x2) { // clear out touch movement data if we have it sticking around // this can occur if touchcancel doesn't fire due to preventdefault, etc. touch.x2 = undefined touch.y2 = undefined } now = date.now() delta = now - (touch.last || now) touch.el = $('tagname' in firsttouch.target ? firsttouch.target : firsttouch.target.parentnode) touchtimeout && cleartimeout(touchtimeout) touch.x1 = firsttouch.pagex touch.y1 = firsttouch.pagey if (delta > 0 && delta <= 250) touch.isdoubletap = true touch.last = now longtaptimeout = settimeout(longtap, longtapdelay) // adds the current touch contact for ie gesture recognition if (gesture && _ispointertype) gesture.addpointer(e.pointerid) }) .on('touchmove mspointermove pointermove', function(e){ if((_ispointertype = ispointereventtype(e, 'move')) && !isprimarytouch(e)) return firsttouch = _ispointertype ? e.originalevent : e.originalevent.touches[0] cancellongtap() touch.x2 = firsttouch.pagex touch.y2 = firsttouch.pagey deltax += math.abs(touch.x1 - touch.x2) deltay += math.abs(touch.y1 - touch.y2) }) .on('touchend mspointerup pointerup', function(e){ if((_ispointertype = ispointereventtype(e, 'up')) && !isprimarytouch(e)) return cancellongtap() // swipe if ((touch.x2 && math.abs(touch.x1 - touch.x2) > 30) || (touch.y2 && math.abs(touch.y1 - touch.y2) > 30)) swipetimeout = settimeout(function() { if (touch.el){ touch.el.trigger('swipe') touch.el.trigger('swipe' + (swipedirection(touch.x1, touch.x2, touch.y1, touch.y2))) } touch = {} }, 0) // normal tap else if ('last' in touch) // don't fire tap when delta position changed by more than 30 pixels, // for instance when moving to a point and back to origin if (deltax < 30 && deltay < 30) { // delay by one tick so we can cancel the 'tap' event if 'scroll' fires // ('tap' fires before 'scroll') taptimeout = settimeout(function() { // trigger universal 'tap' with the option to canceltouch() // (canceltouch cancels processing of single vs double taps for faster 'tap' response) var event = $.event('tap') event.canceltouch = cancelall // [by paper] fix -> "typeerror: 'undefined' is not an object (evaluating 'touch.el.trigger'), when double tap if (touch.el) touch.el.trigger(event) // trigger double tap immediately if (touch.isdoubletap) { if (touch.el) touch.el.trigger('doubletap') touch = {} } // trigger single tap after 250ms of inactivity else { touchtimeout = settimeout(function(){ touchtimeout = null if (touch.el) touch.el.trigger('singletap') touch = {} }, 250) } }, 0) } else { touch = {} } deltax = deltay = 0 }) // when the browser window loses focus, // for example when a modal dialog is shown, // cancel all ongoing events .on('touchcancel mspointercancel pointercancel', cancelall) // scrolling the window indicates intention of the user // to scroll, not tap or swipe, so cancel all ongoing events $(window).on('scroll', cancelall) }) ;['swipe', 'swipeleft', 'swiperight', 'swipeup', 'swipedown', 'doubletap', 'tap', 'singletap', 'longtap'].foreach(function(eventname){ $.fn[eventname] = function(callback){ return this.on(eventname, callback) } }) })(jquery)