PageSourceSearch

https://rededucacioninclusiva.org/wp-content/themes/wp-zefir/js/jquery.mobile.just-touch.js

js rededucacioninclusiva.org collected 2026-10-04 02:27:02 UTC 19,232 bytes, 657 lines download raw bytes

1// This is a combination of two modified files from jQuery Mobile, 
2// jquery.mobile.vmouse.js and jquery.mobile.event.js
3// They were modified to only provide the touch event shortcuts, and 
4// avoid the rest of the jQuery Mobile framework.
5// The normal jQuery Mobile license applies. http://jquery.org/license
6//
7// This plugin is an experiment for abstracting away the touch and mouse
8// events so that developers don't have to worry about which method of input
9// the device their document is loaded on supports.
10//
11// The idea here is to allow the developer to register listeners for the
12// basic mouse events, such as mousedown, mousemove, mouseup, and click,
13// and the plugin will take care of registering the correct listeners
14// behind the scenes to invoke the listener at the fastest possible time
15// for that device, while still retaining the order of event firing in
16// the traditional mouse environment, should multiple handlers be registered
17// on the same element for different events.
18//
19// The current version exposes the following virtual events to jQuery bind methods:
20// "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel"
21
22(function($, window, document, undefined ) {
23$.attrFn = $.attrFn || {};
24var dataPropertyName = "virtualMouseBindings",
25	touchTargetPropertyName = "virtualTouchID",
26	virtualEventNames = "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split( " " ),
27	touchEventProps = "clientX clientY pageX pageY screenX screenY".split( " " ),
28	mouseHookProps = $.event.mouseHooks ? $.event.mouseHooks.props : [],
29	mouseEventProps = $.event.props.concat( mouseHookProps ),
30	activeDocHandlers = {},
31	resetTimerID = 0,
32	startX = 0,
33	startY = 0,
34	didScroll = false,
35	clickBlockList = [],
36	blockMouseTriggers = false,
37	blockTouchTriggers = false,
38	eventCaptureSupported = "addEventListener" in document,
39	$document = $( document ),
40	nextTouchID = 1,
41	lastTouchID = 0;
42
43$.vmouse = {
44	moveDistanceThreshold: 10,
45	clickDistanceThreshold: 10,
46	resetTimerDuration: 1500
47};
48
49function getNativeEvent( event ) {
50
51	while ( event && typeof event.originalEvent !== "undefined" ) {
52		event = event.originalEvent;
53	}
54	return event;
55}
56
57function createVirtualEvent( event, eventType ) {
58
59	var t = event.type,
60		oe, props, ne, prop, ct, touch, i, j;
61
62	event = $.Event(event);
63	event.type = eventType;
64
65	oe = event.originalEvent;
66	props = $.event.props;
67
68	// addresses separation of $.event.props in to $.event.mouseHook.props and Issue 3280
69	// https://github.com/jquery/jquery-mobile/issues/3280
70	if ( t.search( /^(mouse|click)/ ) > -1 ) {
71		props = mouseEventProps;
72	}
73
74	// copy original event properties over to the new event
75	// this would happen if we could call $.event.fix instead of $.Event
76	// but we don't have a way to force an event to be fixed multiple times
77	if ( oe ) {
78		for ( i = props.length, prop; i; ) {
79			prop = props[ --i ];
80			event[ prop ] = oe[ prop ];
81		}
82	}
83
84	// make sure that if the mouse and click virtual events are generated
85	// without a .which one is defined
86	if ( t.search(/mouse(down|up)|click/) > -1 && !event.which ){
87		event.which = 1;
88	}
89
90	if ( t.search(/^touch/) !== -1 ) {
91		ne = getNativeEvent( oe );
92		t = ne.touches;
93		ct = ne.changedTouches;
94		touch = ( t && t.length ) ? t[0] : ( (ct && ct.length) ? ct[ 0 ] : undefined );
95
96		if ( touch ) {
97			for ( j = 0, len = touchEventProps.length; j < len; j++){
98				prop = touchEventProps[ j ];
99				event[ prop ] = touch[ prop ];
100			}
101		}
102	}
103
104	return event;
105}
106
107function getVirtualBindingFlags( element ) {
108
109	var flags = {},
110		b, k;
111
112	while ( element ) {
113
114		b = $.data( element, dataPropertyName );
115
116		for (  k in b ) {
117			if ( b[ k ] ) {
118				flags[ k ] = flags.hasVirtualBinding = true;
119			}
120		}
121		element = element.parentNode;
122	}
123	return flags;
124}
125
126function getClosestElementWithVirtualBinding( element, eventType ) {
127	var b;
128	while ( element ) {
129
130		b = $.data( element, dataPropertyName );
131
132		if ( b && ( !eventType || b[ eventType ] ) ) {
133			return element;
134		}
135		element = element.parentNode;
136	}
137	return null;
138}
139
140function enableTouchBindings() {
141	blockTouchTriggers = false;
142}
143
144function disableTouchBindings() {
145	blockTouchTriggers = true;
146}
147
148function enableMouseBindings() {
149	lastTouchID = 0;
150	clickBlockList.length = 0;
151	blockMouseTriggers = false;
152
153	// When mouse bindings are enabled, our
154	// touch bindings are disabled.
155	disableTouchBindings();
156}
157
158function disableMouseBindings() {
159	// When mouse bindings are disabled, our
160	// touch bindings are enabled.
161	enableTouchBindings();
162}
163
164function startResetTimer() {
165	clearResetTimer();
166	resetTimerID = setTimeout(function(){
167		resetTimerID = 0;
168		enableMouseBindings();
169	}, $.vmouse.resetTimerDuration );
170}
171
172function clearResetTimer() {
173	if ( resetTimerID ){
174		clearTimeout( resetTimerID );
175		resetTimerID = 0;
176	}
177}
178
179function triggerVirtualEvent( eventType, event, flags ) {
180	var ve;
181
182	if ( ( flags && flags[ eventType ] ) ||
183				( !flags && getClosestElementWithVirtualBinding( event.target, eventType ) ) ) {
184
185		ve = createVirtualEvent( event, eventType );
186
187		$( event.target).trigger( ve );
188	}
189
190	return ve;
191}
192
193function mouseEventCallback( event ) {
194	var touchID = $.data(event.target, touchTargetPropertyName);
195
196	if ( !blockMouseTriggers && ( !lastTouchID || lastTouchID !== touchID ) ){
197		var ve = triggerVirtualEvent( "v" + event.type, event );
198		if ( ve ) {
199			if ( ve.isDefaultPrevented() ) {
200				event.preventDefault();
201			}
202			if ( ve.isPropagationStopped() ) {
203				event.stopPropagation();
204			}
205			if ( ve.isImmediatePropagationStopped() ) {
206				event.stopImmediatePropagation();
207			}
208		}
209	}
210}
211
212function handleTouchStart( event ) {
213
214	var touches = getNativeEvent( event ).touches,
215		target, flags;
216
217	if ( touches && touches.length === 1 ) {
218
219		target = event.target;
220		flags = getVirtualBindingFlags( target );
221
222		if ( flags.hasVirtualBinding ) {
223
224			lastTouchID = nextTouchID++;
225			$.data( target, touchTargetPropertyName, lastTouchID );
226
227			clearResetTimer();
228
229			disableMouseBindings();
230			didScroll = false;
231
232			var t = getNativeEvent( event ).touches[ 0 ];
233			startX = t.pageX;
234			startY = t.pageY;
235
236			triggerVirtualEvent( "vmouseover", event, flags );
237			triggerVirtualEvent( "vmousedown", event, flags );
238		}
239	}
240}
241
242function handleScroll( event ) {
243	if ( blockTouchTriggers ) {
244		return;
245	}
246
247	if ( !didScroll ) {
248		triggerVirtualEvent( "vmousecancel", event, getVirtualBindingFlags( event.target ) );
249	}
250
251	didScroll = true;
252	startResetTimer();
253}
254
255function handleTouchMove( event ) {
256	if ( blockTouchTriggers ) {
257		return;
258	}
259
260	var t = getNativeEvent( event ).touches[ 0 ],
261		didCancel = didScroll,
262		moveThreshold = $.vmouse.moveDistanceThreshold;
263		didScroll = didScroll ||
264			( Math.abs(t.pageX - startX) > moveThreshold ||
265				Math.abs(t.pageY - startY) > moveThreshold ),
266		flags = getVirtualBindingFlags( event.target );
267
268	if ( didScroll && !didCancel ) {
269		triggerVirtualEvent( "vmousecancel", event, flags );
270	}
271
272	triggerVirtualEvent( "vmousemove", event, flags );
273	startResetTimer();
274}
275
276function handleTouchEnd( event ) {
277	if ( blockTouchTriggers ) {
278		return;
279	}
280
281	disableTouchBindings();
282
283	var flags = getVirtualBindingFlags( event.target ), t;
284	triggerVirtualEvent( "vmouseup", event, flags );
285
286	if ( !didScroll ) {
287		var ve = triggerVirtualEvent( "vclick", event, flags );
288		if ( ve && ve.isDefaultPrevented() ) {
289			// The target of the mouse events that follow the touchend
290			// event don't necessarily match the target used during the
291			// touch. This means we need to rely on coordinates for blocking
292			// any click that is generated.
293			t = getNativeEvent( event ).changedTouches[ 0 ];
294			clickBlockList.push({
295				touchID: lastTouchID,
296				x: t.clientX,
297				y: t.clientY
298			});
299
300			// Prevent any mouse events that follow from triggering
301			// virtual event notifications.
302			blockMouseTriggers = true;
303		}
304	}
305	triggerVirtualEvent( "vmouseout", event, flags);
306	didScroll = false;
307
308	startResetTimer();
309}
310
311function hasVirtualBindings( ele ) {
312	var bindings = $.data( ele, dataPropertyName ),
313		k;
314
315	if ( bindings ) {
316		for ( k in bindings ) {
317			if ( bindings[ k ] ) {
318				return true;
319			}
320		}
321	}
322	return false;
323}
324
325function dummyMouseHandler(){};
326
327function getSpecialEventObject( eventType ) {
328	var realType = eventType.substr( 1 );
329
330	return {
331		setup: function( data, namespace ) {
332			// If this is the first virtual mouse binding for this element,
333			// add a bindings object to its data.
334
335			if ( !hasVirtualBindings( this ) ) {
336				$.data( this, dataPropertyName, {});
337			}
338
339			// If setup is called, we know it is the first binding for this
340			// eventType, so initialize the count for the eventType to zero.
341			var bindings = $.data( this, dataPropertyName );
342			bindings[ eventType ] = true;
343
344			// If this is the first virtual mouse event for this type,
345			// register a global handler on the document.
346
347			activeDocHandlers[ eventType ] = ( activeDocHandlers[ eventType ] || 0 ) + 1;
348
349			if ( activeDocHandlers[ eventType ] === 1 ) {
350				$document.bind( realType, mouseEventCallback );
351			}
352
353			// Some browsers, like Opera Mini, won't dispatch mouse/click events
354			// for elements unless they actually have handlers registered on them.
355			// To get around this, we register dummy handlers on the elements.
356
357			$(this).bind(realType, dummyMouseHandler);
358
359			// For now, if event capture is not supported, we rely on mouse handlers.
360			if ( eventCaptureSupported ) {
361				// If this is the first virtual mouse binding for the document,
362				// register our touchstart handler on the document.
363
364				activeDocHandlers[ "touchstart" ] = ( activeDocHandlers[ "touchstart" ] || 0) + 1;
365
366				if (activeDocHandlers[ "touchstart" ] === 1) {
367					$document.bind( "touchstart", handleTouchStart )
368						.bind( "touchend", handleTouchEnd )
369
370						// On touch platforms, touching the screen and then dragging your finger
371						// causes the window content to scroll after some distance threshold is
372						// exceeded. On these platforms, a scroll prevents a click event from being
373						// dispatched, and on some platforms, even the touchend is suppressed. To
374						// mimic the suppression of the click event, we need to watch for a scroll
375						// event. Unfortunately, some platforms like iOS don't dispatch scroll
376						// events until *AFTER* the user lifts their finger (touchend). This means
377						// we need to watch both scroll and touchmove events to figure out whether
378						// or not a scroll happenens before the touchend event is fired.
379
380						.bind( "touchmove", handleTouchMove )
381						.bind( "scroll", handleScroll );
382				}
383			}
384		},
385
386		teardown: function( data, namespace ) {
387			// If this is the last virtual binding for this eventType,
388			// remove its global handler from the document.
389
390			--activeDocHandlers[ eventType ];
391
392			if ( !activeDocHandlers[ eventType ] ) {
393				$document.unbind( realType, mouseEventCallback );
394			}
395
396			if ( eventCaptureSupported ) {
397				// If this is the last virtual mouse binding in existence,
398				// remove our document touchstart listener.
399
400				--activeDocHandlers[ "touchstart" ];
401
402				if ( !activeDocHandlers[ "touchstart" ] ) {
403					$document.unbind( "touchstart", handleTouchStart )
404						.unbind( "touchmove", handleTouchMove )
405						.unbind( "touchend", handleTouchEnd )
406						.unbind( "scroll", handleScroll );
407				}
408			}
409
410			var $this = $( this ),
411				bindings = $.data( this, dataPropertyName );
412
413			// teardown may be called when an element was
414			// removed from the DOM. If this is the case,
415			// jQuery core may have already stripped the element
416			// of any data bindings so we need to check it before
417			// using it.
418			if ( bindings ) {
419				bindings[ eventType ] = false;
420			}
421
422			// Unregister the dummy event handler.
423
424			$this.unbind( realType, dummyMouseHandler );
425
426			// If this is the last virtual mouse binding on the
427			// element, remove the binding data from the element.
428
429			if ( !hasVirtualBindings( this ) ) {
430				$this.removeData( dataPropertyName );
431			}
432		}
433	};
434}
435
436// Expose our custom events to the jQuery bind/unbind mechanism.
437
438for ( var i = 0; i < virtualEventNames.length; i++ ){
439	$.event.special[ virtualEventNames[ i ] ] = getSpecialEventObject( virtualEventNames[ i ] );
440}
441
442// Add a capture click handler to block clicks.
443// Note that we require event capture support for this so if the device
444// doesn't support it, we punt for now and rely solely on mouse events.
445if (eventCaptureSupported) {
446	document.addEventListener( "click", function( e ){
447		var cnt = clickBlockList.length,
448			target = e.target,
449			x, y, ele, i, o, touchID;
450
451		if ( cnt ) {
452			x = e.clientX;
453			y = e.clientY;
454			threshold = $.vmouse.clickDistanceThreshold;
455
456			// The idea here is to run through the clickBlockList to see if
457			// the current click event is in the proximity of one of our
458			// vclick events that had preventDefault() called on it. If we find
459			// one, then we block the click.
460			//
461			// Why do we have to rely on proximity?
462			//
463			// Because the target of the touch event that triggered the vclick
464			// can be different from the target of the click event synthesized
465			// by the browser. The target of a mouse/click event that is syntehsized
466			// from a touch event seems to be implementation specific. For example,
467			// some browsers will fire mouse/click events for a link that is near
468			// a touch event, even though the target of the touchstart/touchend event
469			// says the user touched outside the link. Also, it seems that with most
470			// browsers, the target of the mouse/click event is not calculated until the
471			// time it is dispatched, so if you replace an element that you touched
472			// with another element, the target of the mouse/click will be the new
473			// element underneath that point.
474			//
475			// Aside from proximity, we also check to see if the target and any
476			// of its ancestors were the ones that blocked a click. This is necessary
477			// because of the strange mouse/click target calculation done in the
478			// Android 2.1 browser, where if you click on an element, and there is a
479			// mouse/click handler on one of its ancestors, the target will be the
480			// innermost child of the touched element, even if that child is no where
481			// near the point of touch.
482
483			ele = target;
484
485			while (ele) {
486				for ( i = 0; i < cnt; i++ ) {
487					o = clickBlockList[ i ];
488					touchID = 0;
489
490					if ( ( ele === target && Math.abs( o.x - x ) < threshold && Math.abs( o.y - y ) < threshold ) ||
491								$.data( ele, touchTargetPropertyName ) === o.touchID ) {
492						// XXX: We may want to consider removing matches from the block list
493						//      instead of waiting for the reset timer to fire.
494						e.preventDefault();
495						e.stopPropagation();
496						return;
497					}
498				}
499				ele = ele.parentNode;
500			}
501		}
502	}, true);
503}
504})( jQuery, window, document );
505
506
507(function( $, window, undefined ) {// add new event shortcuts
508$.each(("touchstart touchmove touchend tap taphold swipe swipeleft swiperight" ).split(""), function(i, name) {
509	
510		$.fn[name] = function(fn) {
511			return fn ? this.bind(name, fn) : this.trigger(name);
512		};
513		
514		$.attrFn[name] = true;
515	}
516);
517
518function triggerCustomEvent(obj, eventType, event) {
519	var originalType = event.type;
520	event.type = eventType;
521	$.event.dispatch.call( obj, event );	
522	event.type = originalType;
523}
524
525// also handles taphold
526$.event.special.tap = {
527		
528	setup: function() {
529		var thisObject = this,
530			$this = $(thisObject);
531
532			$this.bind( "touchstart", function( event ) {
533
534			if ( event.which && event.which !== 1 ) {
535				return false;
536			}
537
538			var origTarget = event.target,
539				origEvent = event.originalEvent,
540				timer;
541
542			function clearTapTimer() {
543				clearTimeout( timer );
544			}
545
546			function clearTapHandlers() {
547				clearTapTimer();
548
549				$this.unbind( "vclick", clickHandler )
550					.unbind( "vmouseup", clearTapTimer );
551				$( document ).unbind( "vmousecancel", clearTapHandlers );
552			}
553
554			function clickHandler(event) {
555				clearTapHandlers();
556
557				// ONLY trigger a 'tap' event if the start target is
558				// the same as the stop target.
559				if ( origTarget == event.target ) {
560					triggerCustomEvent( thisObject, "tap", event );
561				}
562			}
563
564			$this.bind( "vmouseup", clearTapTimer )
565				.bind( "vclick", clickHandler );
566			$( document ).bind( "vmousecancel", clearTapHandlers );
567
568			timer = setTimeout(function() {
569				triggerCustomEvent(
570					thisObject, "taphold", $.Event( "taphold", { target: origTarget } )
571				);
572			}, 750 );
573		});
574	}
575};
576
577// also handles swipeleft, swiperight
578$.event.special.swipe = {
579	// More than this horizontal displacement, and we will suppress scrolling.
580	scrollSupressionThreshold: 10,
581	
582	// More time than this, and it isn't a swipe.
583	durationThreshold: 1000,
584	
585	// Swipe horizontal displacement must be more than this.
586	horizontalDistanceThreshold: 30,
587	
588	// Swipe vertical displacement must be less than this.
589	verticalDistanceThreshold: 75,  
590
591	setup: function() {
592		var thisObject = this,
593			$this = $( thisObject );
594
595		$this.bind( "touchstart", function( event ) {
596			var data = event.originalEvent.touches ?
597								event.originalEvent.touches[ 0 ] : event,
598				start = {
599					time: ( new Date() ).getTime(),
600					coords: [ data.pageX, data.pageY ],
601					origin: $( event.target )
602				},
603				stop;
604
605			function moveHandler( event ) {
606
607				if ( !start ) {
608					return;
609				}
610
611				var data = event.originalEvent.touches ?
612						event.originalEvent.touches[ 0 ] : event;
613
614				stop = {
615					time: ( new Date() ).getTime(),
616					coords: [ data.pageX, data.pageY ]
617				};
618
619				// prevent scrolling
620				if ( Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.scrollSupressionThreshold ) {
621					event.preventDefault();
622				}
623			}
624			
625			$this.bind( "touchmove", moveHandler )
626				.one( "touchend", function( event ) {
627					$this.unbind( "touchmove", moveHandler );
628
629					if ( start && stop ) {
630						if ( stop.time - start.time < $.event.special.swipe.durationThreshold &&
631								Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.horizontalDistanceThreshold &&
632								Math.abs( start.coords[ 1 ] - stop.coords[ 1 ] ) < $.event.special.swipe.verticalDistanceThreshold ) {
633
634							start.origin.trigger( "swipe" )
635								.trigger( start.coords[0] > stop.coords[ 0 ] ? "swipeleft" : "swiperight" );
636						}
637					}
638					start = stop = undefined;
639				});
640		});
641	}
642};
643
644
645$.each({
646	taphold: "tap",
647	swipeleft: "swipe",
648	swiperight: "swipe"
649}, function( event, sourceEvent ) {
650	$.event.special[ event ] = {
651		setup: function() {
652			$( this ).bind( sourceEvent, $.noop );
653		}
654	};
655});
656
657})( jQuery, this );

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.