/*! UIkit 2.27.2 | www.getuikit.com | © 2014 YOOtheme | MIT License */ // Based on Zeptos touch.js // raw.github.com/madrobby/zepto/master/src/touch.js // Zepto.js may be freely distributed under the MIT license.

;(function($){

if ($.fn.swipeLeft) {
  return;
}

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) {
    if ( touch.el !== undefined ) 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 == event.MSPOINTER_TYPE_TOUCH && event.isPrimary;
}

$(function(){
  var now, delta, deltaX = 0, deltaY = 0, firstTouch;

  if ('MSGesture' in window) {
    gesture = new MSGesture();
    gesture.target = document.body;
  }

  $(document)
    .on('MSGestureEnd gestureend', function(e){

      var swipeDirectionFromVelocity = e.originalEvent.velocityX > 1 ? 'Right' : e.originalEvent.velocityX < -1 ? 'Left' : e.originalEvent.velocityY > 1 ? 'Down' : e.originalEvent.velocityY < -1 ? 'Up' : null;

      if (swipeDirectionFromVelocity && touch.el !== undefined) {
        touch.el.trigger('swipe');
        touch.el.trigger('swipe'+ swipeDirectionFromVelocity);
      }
    })
    // MSPointerDown: for IE10
    // pointerdown: for IE11
    .on('touchstart MSPointerDown pointerdown', function(e){

      if(e.type == 'MSPointerDown' && !isPrimaryTouch(e.originalEvent)) return;

      firstTouch = (e.type == 'MSPointerDown' || e.type == 'pointerdown') ? e : e.originalEvent.touches[0];

      now      = Date.now();
      delta    = now - (touch.last || now);
      touch.el = $('tagName' in firstTouch.target ? firstTouch.target : firstTouch.target.parentNode);

      if(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 (e.originalEvent && e.originalEvent.pointerId && gesture && ( e.type == 'MSPointerDown' || e.type == 'pointerdown' || e.type == 'touchstart' ) ) {
        gesture.addPointer(e.originalEvent.pointerId);
      }

    })
    // MSPointerMove: for IE10
    // pointermove: for IE11
    .on('touchmove MSPointerMove pointermove', function(e){

      if (e.type == 'MSPointerMove' && !isPrimaryTouch(e.originalEvent)) return;

      firstTouch = (e.type == 'MSPointerMove' || e.type == 'pointermove') ? e : 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);
    })
    // MSPointerUp: for IE10
    // pointerup: for IE11
    .on('touchend MSPointerUp pointerup', function(e){

      if (e.type == 'MSPointerUp' && !isPrimaryTouch(e.originalEvent)) 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 !== undefined ) {
            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 (isNaN(deltaX) || (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;
            if ( touch.el !== undefined ) touch.el.trigger(event);

            // trigger double tap immediately
            if (touch.isDoubleTap) {
              if ( touch.el !== undefined ) touch.el.trigger('doubleTap');
              touch = {};
            }

            // trigger single tap after 250ms of inactivity
            else {
              touchTimeout = setTimeout(function(){
                touchTimeout = null;
                if ( touch.el !== undefined ) 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);