PageSourceSearch

https://www.techedt.com/wp-content/plugins/tech-edition-core/modul…/lib/js/jquery.event.move.js?ver=2.1.8

js techedt.com collected 2026-10-01 10:18:58 UTC 14,864 bytes, 634 lines download raw bytes

1// DOM.event.move
2//
3// 2.0.0
4//
5// Stephen Band
6//
7// Triggers 'movestart', 'move' and 'moveend' events after
8// mousemoves following a mousedown cross a distance threshold,
9// similar to the native 'dragstart', 'drag' and 'dragend' events.
10// Move events are throttled to animation frames. Move event objects
11// have the properties:
12//
13// pageX:
14// pageY:     Page coordinates of pointer.
15// startX:
16// startY:    Page coordinates of pointer at movestart.
17// distX:
18// distY:     Distance the pointer has moved since movestart.
19// deltaX:
20// deltaY:    Distance the finger has moved since last event.
21// velocityX:
22// velocityY: Average velocity over last few events.
23
24( function ( fn ) {
25	if ( typeof define === 'function' && define.amd ) {
26		define( [], fn );
27	} else if (
28		typeof module !== 'undefined' &&
29		module !== null &&
30		module.exports
31	) {
32		module.exports = fn;
33	} else {
34		fn();
35	}
36}(function() {
37	const assign = Object.assign || ( window.jQuery && jQuery.extend );
38
39	// Number of pixels a pressed pointer travels before movestart
40	// event is fired.
41	const threshold = 8;
42
43	// Shim for requestAnimationFrame, falling back to timer. See:
44	// see http://paulirish.com/2011/requestanimationframe-for-smart-animating/
45	const requestFrame = ( function() {
46		return (
47			window.requestAnimationFrame ||
48			window.webkitRequestAnimationFrame ||
49			window.mozRequestAnimationFrame ||
50			window.oRequestAnimationFrame ||
51			window.msRequestAnimationFrame ||
52			function ( fn, element ) {
53				return window.setTimeout( function() {
54					fn();
55				}, 25 );
56			}
57		);
58	} )();
59
60	const ignoreTags = {
61		textarea: true,
62		input: true,
63		select: true,
64		button: true,
65	};
66
67	const mouseevents = {
68		move: 'mousemove',
69		cancel: 'mouseup dragstart',
70		end: 'mouseup'
71	};
72
73	const touchevents = {
74		move: 'touchmove',
75		cancel: 'touchend',
76		end: 'touchend',
77	};
78
79	const rspaces = /\s+/;
80
81	// DOM Events
82
83	const eventOptions = { bubbles: true, cancelable: true };
84
85	const eventsSymbol = Symbol( 'events' );
86
87	function createEvent( type ) {
88		return new CustomEvent( type, eventOptions );
89	}
90
91	function getEvents( node ) {
92		return node[ eventsSymbol ] || ( node[ eventsSymbol ] = {} );
93	}
94
95	function on( node, types, fn, data, selector ) {
96		types = types.split( rspaces );
97
98		const events = getEvents( node );
99		let i = types.length;
100		let handlers, type;
101
102		function handler( e ) {
103			fn( e, data );
104		}
105
106		while ( i-- ) {
107			type = types[ i ];
108			handlers = events[ type ] || ( events[ type ] = [] );
109			handlers.push( [ fn, handler ] );
110			node.addEventListener( type, handler );
111		}
112	}
113
114	function off( node, types, fn, selector ) {
115		types = types.split( rspaces );
116
117		const events = getEvents( node );
118		let i = types.length;
119		let type, handlers, k;
120
121		if ( ! events ) {
122			return;
123		}
124
125		while ( i-- ) {
126			type = types[ i ];
127			handlers = events[ type ];
128			if ( ! handlers ) {
129				continue;
130			}
131			k = handlers.length;
132			while ( k-- ) {
133				if ( handlers[ k ][ 0 ] === fn ) {
134					node.removeEventListener( type, handlers[ k ][ 1 ] );
135					handlers.splice( k, 1 );
136				}
137			}
138		}
139	}
140
141	function trigger( node, type, properties ) {
142		// Don't cache events. It prevents you from triggering an event of a
143		// given type from inside the handler of another event of that type.
144		const event = createEvent( type );
145		if ( properties ) {
146			assign( event, properties );
147		}
148		node.dispatchEvent( event );
149	}
150
151	// Constructors
152
153	function Timer( fn ) {
154		let callback = fn,
155			active = false,
156			running = false;
157
158		function trigger( time ) {
159			if ( active ) {
160				callback();
161				requestFrame( trigger );
162				running = true;
163				active = false;
164			} else {
165				running = false;
166			}
167		}
168
169		this.kick = function ( fn ) {
170			active = true;
171			if ( ! running ) {
172				trigger();
173			}
174		};
175
176		this.end = function ( fn ) {
177			const cb = callback;
178
179			if ( ! fn ) {
180				return;
181			}
182
183			// If the timer is not running, simply call the end callback.
184			if ( ! running ) {
185				fn();
186			}
187			// If the timer is running, and has been kicked lately, then
188			// queue up the current callback and the end callback, otherwise
189			// just the end callback.
190			else {
191				callback = active
192					? function () {
193						cb();
194						fn();
195					  }
196					: fn;
197
198				active = true;
199			}
200		};
201	}
202
203	// Functions
204
205	function noop() {}
206
207	function preventDefault( e ) {
208		e.preventDefault();
209	}
210
211	function isIgnoreTag( e ) {
212		return (
213			!! e.target.tagName &&
214			!! ignoreTags[ e.target.tagName.toLowerCase() ]
215		);
216	}
217
218	function isPrimaryButton( e ) {
219		// Ignore mousedowns on any button other than the left (or primary)
220		// mouse button, or when a modifier key is pressed.
221		return e.which === 1 && ! e.ctrlKey && ! e.altKey;
222	}
223
224	function identifiedTouch( touchList, id ) {
225		let i, l;
226
227		if ( touchList.identifiedTouch ) {
228			return touchList.identifiedTouch( id );
229		}
230
231		// touchList.identifiedTouch() does not exist in
232		// webkit yet… we must do the search ourselves...
233
234		i = -1;
235		l = touchList.length;
236
237		while ( ++i < l ) {
238			if ( touchList[ i ].identifier === id ) {
239				return touchList[ i ];
240			}
241		}
242	}
243
244	function changedTouch( e, data ) {
245		const touch = identifiedTouch( e.changedTouches, data.identifier );
246
247		// This isn't the touch you're looking for.
248		if ( ! touch ) {
249			return;
250		}
251
252		// Chrome Android (at least) includes touches that have not
253		// changed in e.changedTouches. That's a bit annoying. Check
254		// that this touch has changed.
255		if ( touch.pageX === data.pageX && touch.pageY === data.pageY ) {
256			return;
257		}
258
259		return touch;
260	}
261
262	// Handlers that decide when the first movestart is triggered
263
264	function mousedown( e ) {
265		// Ignore non-primary buttons
266		if ( ! isPrimaryButton( e ) ) {
267			return;
268		}
269
270		// Ignore form and interactive elements
271		if ( isIgnoreTag( e ) ) {
272			return;
273		}
274
275		on( document, mouseevents.move, mousemove, e );
276		on( document, mouseevents.cancel, mouseend, e );
277	}
278
279	function mousemove( e, data ) {
280		checkThreshold( e, data, e, removeMouse );
281	}
282
283	function mouseend( e, data ) {
284		removeMouse();
285	}
286
287	function removeMouse() {
288		off( document, mouseevents.move, mousemove );
289		off( document, mouseevents.cancel, mouseend );
290	}
291
292	function touchstart( e ) {
293		// Don't get in the way of interaction with form elements
294		if ( ignoreTags[ e.target.tagName.toLowerCase() ] ) {
295			return;
296		}
297
298		const touch = e.changedTouches[ 0 ];
299
300		// iOS live updates the touch objects whereas Android gives us copies.
301		// That means we can't trust the touchstart object to stay the same,
302		// so we must copy the data. This object acts as a template for
303		// movestart, move and moveend event objects.
304		const data = {
305			target: touch.target,
306			pageX: touch.pageX,
307			pageY: touch.pageY,
308			identifier: touch.identifier,
309
310			// The only way to make handlers individually unbindable is by
311			// making them unique.
312			touchmove(e, data) { touchmove(e, data); },
313			touchend(e, data) { touchend(e, data); }
314		};
315
316		on( document, touchevents.move, data.touchmove, data );
317		on( document, touchevents.cancel, data.touchend, data );
318	}
319
320	function touchmove( e, data ) {
321		const touch = changedTouch( e, data );
322		if ( ! touch ) {
323			return;
324		}
325		checkThreshold( e, data, touch, removeTouch );
326	}
327
328	function touchend( e, data ) {
329		const touch = identifiedTouch( e.changedTouches, data.identifier );
330		if ( ! touch ) {
331			return;
332		}
333		removeTouch( data );
334	}
335
336	function removeTouch( data ) {
337		off( document, touchevents.move, data.touchmove );
338		off( document, touchevents.cancel, data.touchend );
339	}
340
341	function checkThreshold( e, data, touch, fn ) {
342		const distX = touch.pageX - data.pageX;
343		const distY = touch.pageY - data.pageY;
344
345		// Do nothing if the threshold has not been crossed.
346		if ( distX * distX + distY * distY < threshold * threshold ) {
347			return;
348		}
349
350		triggerStart( e, data, touch, distX, distY, fn );
351	}
352
353	function triggerStart( e, data, touch, distX, distY, fn ) {
354		const touches = e.targetTouches;
355		const time = e.timeStamp - data.timeStamp;
356
357		// Create a movestart object with some special properties that
358		// are passed only to the movestart handlers.
359		const template = {
360			altKey: e.altKey,
361			ctrlKey: e.ctrlKey,
362			shiftKey: e.shiftKey,
363			startX: data.pageX,
364			startY: data.pageY,
365			distX,
366			distY,
367			deltaX: distX,
368			deltaY: distY,
369			pageX: touch.pageX,
370			pageY: touch.pageY,
371			velocityX: distX / time,
372			velocityY: distY / time,
373			identifier: data.identifier,
374			targetTouches: touches,
375			finger: touches ? touches.length : 1,
376			enableMove() {
377				this.moveEnabled = true;
378				this.enableMove = noop;
379				e.preventDefault();
380			}
381		};
382
383		// Trigger the movestart event.
384		trigger( data.target, 'movestart', template );
385
386		// Unbind handlers that tracked the touch or mouse up till now.
387		fn( data );
388	}
389
390	// Handlers that control what happens following a movestart
391
392	function activeMousemove( e, data ) {
393		const timer = data.timer;
394
395		data.touch = e;
396		data.timeStamp = e.timeStamp;
397		timer.kick();
398	}
399
400	function activeMouseend( e, data ) {
401		const target = data.target;
402		const event = data.event;
403		const timer = data.timer;
404
405		removeActiveMouse();
406
407		endEvent( target, event, timer, function () {
408			// Unbind the click suppressor, waiting until after mouseup
409			// has been handled.
410			setTimeout( function () {
411				off( target, 'click', preventDefault );
412			}, 0 );
413		} );
414	}
415
416	function removeActiveMouse() {
417		off( document, mouseevents.move, activeMousemove );
418		off( document, mouseevents.end, activeMouseend );
419	}
420
421	function activeTouchmove( e, data ) {
422		const event = data.event;
423		const timer = data.timer;
424		const touch = changedTouch( e, event );
425
426		if ( ! touch ) {
427			return;
428		}
429
430		// Stop the interface from gesturing
431		e.preventDefault();
432
433		event.targetTouches = e.targetTouches;
434		data.touch = touch;
435		data.timeStamp = e.timeStamp;
436
437		timer.kick();
438	}
439
440	function activeTouchend( e, data ) {
441		const target = data.target;
442		const event = data.event;
443		const timer = data.timer;
444		const touch = identifiedTouch( e.changedTouches, event.identifier );
445
446		// This isn't the touch you're looking for.
447		if ( ! touch ) {
448			return;
449		}
450
451		removeActiveTouch( data );
452		endEvent( target, event, timer );
453	}
454
455	function removeActiveTouch( data ) {
456		off( document, touchevents.move, data.activeTouchmove );
457		off( document, touchevents.end, data.activeTouchend );
458	}
459
460	// Logic for triggering move and moveend events
461
462	function updateEvent( event, touch, timeStamp ) {
463		const time = timeStamp - event.timeStamp;
464
465		event.distX = touch.pageX - event.startX;
466		event.distY = touch.pageY - event.startY;
467		event.deltaX = touch.pageX - event.pageX;
468		event.deltaY = touch.pageY - event.pageY;
469
470		// Average the velocity of the last few events using a decay
471		// curve to even out spurious jumps in values.
472		event.velocityX = 0.3 * event.velocityX + ( 0.7 * event.deltaX ) / time;
473		event.velocityY = 0.3 * event.velocityY + ( 0.7 * event.deltaY ) / time;
474		event.pageX = touch.pageX;
475		event.pageY = touch.pageY;
476	}
477
478	function endEvent( target, event, timer, fn ) {
479		timer.end( function () {
480			trigger( target, 'moveend', event );
481			return fn && fn();
482		} );
483	}
484
485	// Set up the DOM
486
487	function movestart( e ) {
488		if ( e.defaultPrevented ) {
489			return;
490		}
491		if ( ! e.moveEnabled ) {
492			return;
493		}
494
495		const event = {
496			startX: e.startX,
497			startY: e.startY,
498			pageX: e.pageX,
499			pageY: e.pageY,
500			distX: e.distX,
501			distY: e.distY,
502			deltaX: e.deltaX,
503			deltaY: e.deltaY,
504			velocityX: e.velocityX,
505			velocityY: e.velocityY,
506			identifier: e.identifier,
507			targetTouches: e.targetTouches,
508			finger: e.finger,
509		};
510
511		const data = {
512			target: e.target,
513			event,
514			timer: new Timer( update ),
515			touch: undefined,
516			timeStamp: e.timeStamp,
517		};
518
519		function update( time ) {
520			updateEvent( event, data.touch, data.timeStamp );
521			trigger( data.target, 'move', event );
522		}
523
524		if ( e.identifier === undefined ) {
525			// We're dealing with a mouse event.
526			// Stop clicks from propagating during a move
527			on( e.target, 'click', preventDefault );
528			on( document, mouseevents.move, activeMousemove, data );
529			on( document, mouseevents.end, activeMouseend, data );
530		} else {
531			// In order to unbind correct handlers they have to be unique
532			data.activeTouchmove = function ( e, data ) {
533				activeTouchmove( e, data );
534			};
535			data.activeTouchend = function ( e, data ) {
536				activeTouchend( e, data );
537			};
538
539			// We're dealing with a touch.
540			on( document, touchevents.move, data.activeTouchmove, data );
541			on( document, touchevents.end, data.activeTouchend, data );
542		}
543	}
544
545	on( document, 'mousedown', mousedown );
546	on( document, 'touchstart', touchstart );
547	on( document, 'movestart', movestart );
548
549	// jQuery special events
550	//
551	// jQuery event objects are copies of DOM event objects. They need
552	// a little help copying the move properties across.
553
554	if ( ! window.jQuery ) {
555		return;
556	}
557
558	const properties =
559		'startX startY pageX pageY distX distY deltaX deltaY velocityX velocityY'.split(
560			' '
561		);
562
563	function enableMove1( e ) {
564		e.enableMove();
565	}
566	function enableMove2( e ) {
567		e.enableMove();
568	}
569	function enableMove3( e ) {
570		e.enableMove();
571	}
572
573	function add( handleObj ) {
574		const handler = handleObj.handler;
575
576		handleObj.handler = function ( e ) {
577			// Copy move properties across from originalEvent
578			let i = properties.length;
579			let property;
580
581			while ( i-- ) {
582				property = properties[ i ];
583				e[ property ] = e.originalEvent[ property ];
584			}
585
586			handler.apply( this, arguments );
587		};
588	}
589
590	jQuery.event.special.movestart = {
591		setup() {
592			// Movestart must be enabled to allow other move events
593			on( this, 'movestart', enableMove1 );
594
595			// Do listen to DOM events
596			return false;
597		},
598
599		teardown() {
600			off( this, 'movestart', enableMove1 );
601			return false;
602		},
603
604		add,
605	};
606
607	jQuery.event.special.move = {
608		setup() {
609			on( this, 'movestart', enableMove2 );
610			return false;
611		},
612
613		teardown() {
614			off( this, 'movestart', enableMove2 );
615			return false;
616		},
617
618		add,
619	};
620
621	jQuery.event.special.moveend = {
622		setup() {
623			on( this, 'movestart', enableMove3 );
624			return false;
625		},
626
627		teardown() {
628			off( this, 'movestart', enableMove3 );
629			return false;
630		},
631
632		add,
633	};
634} ));

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.