PageSourceSearch

https://pinnerdentist.co.uk/wp-content/themes/pinnergreendental/js/event-move.js

js pinnerdentist.co.uk collected 2026-10-05 18:57:49 UTC 14,565 bytes, 601 lines download raw bytes

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

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.