| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580 | // jquery.event.move//// 1.3.1//// Stephen Band//// Triggers 'movestart', 'move' and 'moveend' events after// mousemoves following a mousedown cross a distance threshold,// similar to the native 'dragstart', 'drag' and 'dragend' events.// Move events are throttled to animation frames. Move event objects// have the properties://// pageX:// pageY:   Page coordinates of pointer.// startX:// startY:  Page coordinates of pointer at movestart.// distX:// distY:  Distance the pointer has moved since movestart.// deltaX:// deltaY:  Distance the finger has moved since last event.// velocityX:// velocityY:  Average velocity over last few events.(function (module) {	if (typeof define === 'function' && define.amd) {		// AMD. Register as an anonymous module.		define(['jquery'], module);	} else {		// Browser globals		module(jQuery);	}})(function(jQuery, undefined){	var // Number of pixels a pressed pointer travels before movestart	    // event is fired.	    threshold = 6,		    add = jQuery.event.add,		    remove = jQuery.event.remove,	    // Just sugar, so we can have arguments in the same order as	    // add and remove.	    trigger = function(node, type, data) {	    	jQuery.event.trigger(type, data, node);	    },	    // Shim for requestAnimationFrame, falling back to timer. See:	    // see http://paulirish.com/2011/requestanimationframe-for-smart-animating/	    requestFrame = (function(){	    	return (	    		window.requestAnimationFrame ||	    		window.webkitRequestAnimationFrame ||	    		window.mozRequestAnimationFrame ||	    		window.oRequestAnimationFrame ||	    		window.msRequestAnimationFrame ||	    		function(fn, element){	    			return window.setTimeout(function(){	    				fn();	    			}, 25);	    		}	    	);	    })(),	    	    ignoreTags = {	    	textarea: true,	    	input: true,	    	select: true,	    	button: true	    },	    	    mouseevents = {	    	move: 'mousemove',	    	cancel: 'mouseup dragstart',	    	end: 'mouseup'	    },	    	    touchevents = {	    	move: 'touchmove',	    	cancel: 'touchend',	    	end: 'touchend'	    };	// Constructors		function Timer(fn){		var callback = fn,				active = false,				running = false;				function trigger(time) {			if (active){				callback();				requestFrame(trigger);				running = true;				active = false;			}			else {				running = false;			}		}				this.kick = function(fn) {			active = true;			if (!running) { trigger(); }		};				this.end = function(fn) {			var cb = callback;						if (!fn) { return; }						// If the timer is not running, simply call the end callback.			if (!running) {				fn();			}			// If the timer is running, and has been kicked lately, then			// queue up the current callback and the end callback, otherwise			// just the end callback.			else {				callback = active ?					function(){ cb(); fn(); } : 					fn ;								active = true;			}		};	}	// Functions		function returnTrue() {		return true;	}		function returnFalse() {		return false;	}		function preventDefault(e) {		e.preventDefault();	}		function preventIgnoreTags(e) {		// Don't prevent interaction with form elements.		if (ignoreTags[ e.target.tagName.toLowerCase() ]) { return; }				e.preventDefault();	}	function isLeftButton(e) {		// Ignore mousedowns on any button other than the left (or primary)		// mouse button, or when a modifier key is pressed.		return (e.which === 1 && !e.ctrlKey && !e.altKey);	}	function identifiedTouch(touchList, id) {		var i, l;		if (touchList.identifiedTouch) {			return touchList.identifiedTouch(id);		}				// touchList.identifiedTouch() does not exist in		// webkit yet… we must do the search ourselves...				i = -1;		l = touchList.length;				while (++i < l) {			if (touchList[i].identifier === id) {				return touchList[i];			}		}	}	function changedTouch(e, event) {		var touch = identifiedTouch(e.changedTouches, event.identifier);		// This isn't the touch you're looking for.		if (!touch) { return; }		// Chrome Android (at least) includes touches that have not		// changed in e.changedTouches. That's a bit annoying. Check		// that this touch has changed.		if (touch.pageX === event.pageX && touch.pageY === event.pageY) { return; }		return touch;	}	// Handlers that decide when the first movestart is triggered		function mousedown(e){		var data;		if (!isLeftButton(e)) { return; }		data = {			target: e.target,			startX: e.pageX,			startY: e.pageY,			timeStamp: e.timeStamp		};		add(document, mouseevents.move, mousemove, data);		add(document, mouseevents.cancel, mouseend, data);	}	function mousemove(e){		var data = e.data;		checkThreshold(e, data, e, removeMouse);	}	function mouseend(e) {		removeMouse();	}	function removeMouse() {		remove(document, mouseevents.move, mousemove);		remove(document, mouseevents.cancel, mouseend);	}	function touchstart(e) {		var touch, template;		// Don't get in the way of interaction with form elements.		if (ignoreTags[ e.target.tagName.toLowerCase() ]) { return; }		touch = e.changedTouches[0];				// iOS live updates the touch objects whereas Android gives us copies.		// That means we can't trust the touchstart object to stay the same,		// so we must copy the data. This object acts as a template for		// movestart, move and moveend event objects.		template = {			target: touch.target,			startX: touch.pageX,			startY: touch.pageY,			timeStamp: e.timeStamp,			identifier: touch.identifier		};		// Use the touch identifier as a namespace, so that we can later		// remove handlers pertaining only to this touch.		add(document, touchevents.move + '.' + touch.identifier, touchmove, template);		add(document, touchevents.cancel + '.' + touch.identifier, touchend, template);	}	function touchmove(e){		var data = e.data,		    touch = changedTouch(e, data);		if (!touch) { return; }		checkThreshold(e, data, touch, removeTouch);	}	function touchend(e) {		var template = e.data,		    touch = identifiedTouch(e.changedTouches, template.identifier);		if (!touch) { return; }		removeTouch(template.identifier);	}	function removeTouch(identifier) {		remove(document, '.' + identifier, touchmove);		remove(document, '.' + identifier, touchend);	}	// Logic for deciding when to trigger a movestart.	function checkThreshold(e, template, touch, fn) {		var distX = touch.pageX - template.startX,		    distY = touch.pageY - template.startY;		// Do nothing if the threshold has not been crossed.		if ((distX * distX) + (distY * distY) < (threshold * threshold)) { return; }		triggerStart(e, template, touch, distX, distY, fn);	}	function handled() {		// this._handled should return false once, and after return true.		this._handled = returnTrue;		return false;	}	function flagAsHandled(e) {		e._handled();	}	function triggerStart(e, template, touch, distX, distY, fn) {		var node = template.target,		    touches, time;		touches = e.targetTouches;		time = e.timeStamp - template.timeStamp;		// Create a movestart object with some special properties that		// are passed only to the movestart handlers.		template.type = 'movestart';		template.distX = distX;		template.distY = distY;		template.deltaX = distX;		template.deltaY = distY;		template.pageX = touch.pageX;		template.pageY = touch.pageY;		template.velocityX = distX / time;		template.velocityY = distY / time;		template.targetTouches = touches;		template.finger = touches ?			touches.length :			1 ;		// The _handled method is fired to tell the default movestart		// handler that one of the move events is bound.		template._handled = handled;					// Pass the touchmove event so it can be prevented if or when		// movestart is handled.		template._preventTouchmoveDefault = function() {			e.preventDefault();		};		// Trigger the movestart event.		trigger(template.target, template);		// Unbind handlers that tracked the touch or mouse up till now.		fn(template.identifier);	}	// Handlers that control what happens following a movestart	function activeMousemove(e) {		var event = e.data.event,		    timer = e.data.timer;		updateEvent(event, e, e.timeStamp, timer);	}	function activeMouseend(e) {		var event = e.data.event,		    timer = e.data.timer;				removeActiveMouse();		endEvent(event, timer, function() {			// Unbind the click suppressor, waiting until after mouseup			// has been handled.			setTimeout(function(){				remove(event.target, 'click', returnFalse);			}, 0);		});	}	function removeActiveMouse(event) {		remove(document, mouseevents.move, activeMousemove);		remove(document, mouseevents.end, activeMouseend);	}	function activeTouchmove(e) {		var event = e.data.event,		    timer = e.data.timer,		    touch = changedTouch(e, event);		if (!touch) { return; }		// Stop the interface from gesturing		e.preventDefault();		event.targetTouches = e.targetTouches;		updateEvent(event, touch, e.timeStamp, timer);	}	function activeTouchend(e) {		var event = e.data.event,		    timer = e.data.timer,		    touch = identifiedTouch(e.changedTouches, event.identifier);		// This isn't the touch you're looking for.		if (!touch) { return; }		removeActiveTouch(event);		endEvent(event, timer);	}	function removeActiveTouch(event) {		remove(document, '.' + event.identifier, activeTouchmove);		remove(document, '.' + event.identifier, activeTouchend);	}	// Logic for triggering move and moveend events	function updateEvent(event, touch, timeStamp, timer) {		var time = timeStamp - event.timeStamp;		event.type = 'move';		event.distX =  touch.pageX - event.startX;		event.distY =  touch.pageY - event.startY;		event.deltaX = touch.pageX - event.pageX;		event.deltaY = touch.pageY - event.pageY;				// Average the velocity of the last few events using a decay		// curve to even out spurious jumps in values.		event.velocityX = 0.3 * event.velocityX + 0.7 * event.deltaX / time;		event.velocityY = 0.3 * event.velocityY + 0.7 * event.deltaY / time;		event.pageX =  touch.pageX;		event.pageY =  touch.pageY;		timer.kick();	}	function endEvent(event, timer, fn) {		timer.end(function(){			event.type = 'moveend';			trigger(event.target, event);						return fn && fn();		});	}	// jQuery special event definition	function setup(data, namespaces, eventHandle) {		// Stop the node from being dragged		//add(this, 'dragstart.move drag.move', preventDefault);				// Prevent text selection and touch interface scrolling		//add(this, 'mousedown.move', preventIgnoreTags);				// Tell movestart default handler that we've handled this		add(this, 'movestart.move', flagAsHandled);		// Don't bind to the DOM. For speed.		return true;	}		function teardown(namespaces) {		remove(this, 'dragstart drag', preventDefault);		remove(this, 'mousedown touchstart', preventIgnoreTags);		remove(this, 'movestart', flagAsHandled);				// Don't bind to the DOM. For speed.		return true;	}		function addMethod(handleObj) {		// We're not interested in preventing defaults for handlers that		// come from internal move or moveend bindings		if (handleObj.namespace === "move" || handleObj.namespace === "moveend") {			return;		}				// Stop the node from being dragged		add(this, 'dragstart.' + handleObj.guid + ' drag.' + handleObj.guid, preventDefault, undefined, handleObj.selector);				// Prevent text selection and touch interface scrolling		add(this, 'mousedown.' + handleObj.guid, preventIgnoreTags, undefined, handleObj.selector);	}		function removeMethod(handleObj) {		if (handleObj.namespace === "move" || handleObj.namespace === "moveend") {			return;		}				remove(this, 'dragstart.' + handleObj.guid + ' drag.' + handleObj.guid);		remove(this, 'mousedown.' + handleObj.guid);	}		jQuery.event.special.movestart = {		setup: setup,		teardown: teardown,		add: addMethod,		remove: removeMethod,		_default: function(e) {			var template, data;						// If no move events were bound to any ancestors of this			// target, high tail it out of here.			if (!e._handled()) { return; }			template = {				target: e.target,				startX: e.startX,				startY: e.startY,				pageX: e.pageX,				pageY: e.pageY,				distX: e.distX,				distY: e.distY,				deltaX: e.deltaX,				deltaY: e.deltaY,				velocityX: e.velocityX,				velocityY: e.velocityY,				timeStamp: e.timeStamp,				identifier: e.identifier,				targetTouches: e.targetTouches,				finger: e.finger			};			data = {				event: template,				timer: new Timer(function(time){					trigger(e.target, template);				})			};						if (e.identifier === undefined) {				// We're dealing with a mouse				// Stop clicks from propagating during a move				add(e.target, 'click', returnFalse);				add(document, mouseevents.move, activeMousemove, data);				add(document, mouseevents.end, activeMouseend, data);			}			else {				// We're dealing with a touch. Stop touchmove doing				// anything defaulty.				e._preventTouchmoveDefault();				add(document, touchevents.move + '.' + e.identifier, activeTouchmove, data);				add(document, touchevents.end + '.' + e.identifier, activeTouchend, data);			}		}	};	jQuery.event.special.move = {		setup: function() {			// Bind a noop to movestart. Why? It's the movestart			// setup that decides whether other move events are fired.			add(this, 'movestart.move', jQuery.noop);		},				teardown: function() {			remove(this, 'movestart.move', jQuery.noop);		}	};		jQuery.event.special.moveend = {		setup: function() {			// Bind a noop to movestart. Why? It's the movestart			// setup that decides whether other move events are fired.			add(this, 'movestart.moveend', jQuery.noop);		},				teardown: function() {			remove(this, 'movestart.moveend', jQuery.noop);		}	};	add(document, 'mousedown.move', mousedown);	add(document, 'touchstart.move', touchstart);	// Make jQuery copy touch event properties over to the jQuery event	// object, if they are not already listed. But only do the ones we	// really need. IE7/8 do not have Array#indexOf(), but nor do they	// have touch events, so let's assume we can ignore them.	if (typeof Array.prototype.indexOf === 'function') {		(function(jQuery, undefined){			var props = ["changedTouches", "targetTouches"],			    l = props.length;						while (l--) {				if (jQuery.event.props.indexOf(props[l]) === -1) {					jQuery.event.props.push(props[l]);				}			}		})(jQuery);	};});
 |