/** * * @name: mnTouch * @version: 1.3.2 * @description: Ultrafast AngularJS touch events directive (tap, hold and swipe) * @author: Alessandro Bellini - ilmente * @license: MIT * */ "use strict"; angular.module("mn", []).directive("mnTouch", [ "$timeout", function($timeout) { var touchEngine = function(scope, element, attrs) { scope.$event = { name: "", isSecure: false, isRunning: false, target: element[0], threshold: !!attrs.threshold ? attrs.threshold : 10, holdfor: !!attrs.holdfor ? attrs.holdfor : 500, types: { start: "mousedown", move: "mousemove", end: "mouseup", cancel: "" }, time: {}, coords: {}, events: {}, directionX: 0, directionY: 0, offsetX: 0, offsetY: 0 }; var fn = function(eventName) { scope.$event.name = eventName; if (!!attrs[eventName]) { scope.$eval(attrs[eventName]); scope.$apply(); } }; var getCoords = function(event) { return { x: event.pageX || 0, y: event.pageY || 0 }; }; if (typeof window.ontouchstart !== "undefined" && typeof window.ontouchend !== "undefined" && typeof window.ontouchcancel !== "undefined") { scope.$event.types.start = "touchstart"; scope.$event.types.move = "touchmove"; scope.$event.types.end = "touchend"; scope.$event.types.cancel = "touchcancel"; getCoords = function(event) { var coords = !!event && !!event.changedTouches && !!event.changedTouches.length > 0 ? event.changedTouches[0] : {}; return { x: coords.pageX || event.pageX || 0, y: coords.pageY || event.pageY || 0 }; }; } else if (window.navigator.pointerEnabled) { scope.$event.types.start = "pointerdown"; scope.$event.types.move = "pointermove"; scope.$event.types.end = "pointerup"; } else if (window.navigator.msPointerEnabled) { scope.$event.types.start = "MSPointerDown"; scope.$event.types.move = "MSPointerMove"; scope.$event.types.end = "MSPointerUp"; scope.$event.types.cancel = "MSPointerOut"; } if (!!attrs["tap"]) { scope.$event.isSecure = false; scope.$event.isRunning = false; var onStartEvent = function(startEvent) { scope.$event.events.start = startEvent; scope.$event.coords.start = getCoords(startEvent); fn("tap"); }; scope.$event.target.addEventListener(scope.$event.types.start, onStartEvent, false); } else { scope.$event.isSecure = true; var holdPromise = null; var onStartEvent = function(startEvent) { scope.$event.isRunning = true; scope.$event.time.start = new Date().getTime(); scope.$event.events.start = startEvent; scope.$event.coords.start = getCoords(startEvent); if (!!attrs["hold"]) { holdPromise = $timeout(function() { onEndEvent(scope.$event.events.move || startEvent); }, scope.$event.holdfor, false); } }; var onMoveEvent = function(moveEvent) { if (scope.$event.isRunning) { scope.$event.events.move = moveEvent; } }; var onEndEvent = function(endEvent) { if (!!holdPromise) $timeout.cancel(holdPromise); if (scope.$event.isRunning) { scope.$event.isRunning = false; scope.$event.time.end = new Date().getTime(); scope.$event.time.duration = scope.$event.time.end - scope.$event.time.start; scope.$event.events.end = endEvent; scope.$event.coords.end = getCoords(endEvent); scope.$event.directionX = scope.$event.coords.end.x - scope.$event.coords.start.x; scope.$event.directionY = scope.$event.coords.end.y - scope.$event.coords.start.y; scope.$event.offsetX = Math.abs(scope.$event.directionX); scope.$event.offsetY = Math.abs(scope.$event.directionY); if (scope.$event.offsetX <= scope.$event.threshold && scope.$event.offsetY <= scope.$event.threshold) { if (!!attrs["hold"] && scope.$event.time.duration >= scope.$event.holdfor) fn("hold"); else fn("secureTap"); } else if (scope.$event.offsetX >= scope.$event.offsetY) fn(scope.$event.directionX > 0 ? "swipeRight" : "swipeLeft"); else fn(scope.$event.directionY > 0 ? "swipeDown" : "swipeUp"); } }; scope.$event.target.addEventListener(scope.$event.types.start, onStartEvent, false); scope.$event.target.addEventListener(scope.$event.types.end, onEndEvent, false); if (!!scope.$event.types.cancel) scope.$event.target.addEventListener(scope.$event.types.cancel, onEndEvent, false); if (!!attrs["hold"]) scope.$event.target.addEventListener(scope.$event.types.move, onMoveEvent, false); } }; return { restrict: "A", link: touchEngine }; } ]);