PageSourceSearch

https://www.ristorantesotajarchi.it/js/smooth-scroll.js

js ristorantesotajarchi.it collected 2026-10-04 20:54:30 UTC 16,767 bytes, 569 lines download raw bytes

1(function (root, factory) {
2	if ( typeof define === 'function' && define.amd ) {
3		define([], function () {
4			return factory(root);
5		});
6	} else if ( typeof exports === 'object' ) {
7		module.exports = factory(root);
8	} else {
9		root.SmoothScroll = factory(root);
10	}
11})(typeof global !== 'undefined' ? global : typeof window !== 'undefined' ? window : this, function (window) {
12
13	'use strict';
14
15	//
16	// Feature Test
17	//
18
19	var supports =
20		'querySelector' in document &&
21		'addEventListener' in window &&
22		'requestAnimationFrame' in window &&
23		'closest' in window.Element.prototype;
24
25
26	//
27	// Default settings
28	//
29
30	var defaults = {
31		// Selectors
32		ignore: '[data-scroll-ignore]',
33		header: null,
34
35		// Speed & Easing
36		speed: 500,
37		offset: 0,
38		easing: 'easeInOutCubic',
39		customEasing: null,
40
41		// Callback API
42		before: function () {},
43		after: function () {}
44	};
45
46
47	//
48	// Utility Methods
49	//
50
51	/**
52	 * Merge two or more objects. Returns a new object.
53	 * @param {Object}   objects  The objects to merge together
54	 * @returns {Object}          Merged values of defaults and options
55	 */
56	var extend = function () {
57
58		// Variables
59		var extended = {};
60		var deep = false;
61		var i = 0;
62		var length = arguments.length;
63
64		// Merge the object into the extended object
65		var merge = function (obj) {
66			for (var prop in obj) {
67				if (obj.hasOwnProperty(prop)) {
68					extended[prop] = obj[prop];
69				}
70			}
71		};
72
73		// Loop through each object and conduct a merge
74		for ( ; i < length; i++ ) {
75			var obj = arguments[i];
76			merge(obj);
77		}
78
79		return extended;
80
81	};
82
83	/**
84	 * Get the height of an element.
85	 * @param  {Node} elem The element to get the height of
86	 * @return {Number}    The element's height in pixels
87	 */
88	var getHeight = function (elem) {
89		return parseInt(window.getComputedStyle(elem).height, 10);
90	};
91
92	/**
93	 * Escape special characters for use with querySelector
94	 * @param {String} id The anchor ID to escape
95	 * @author Mathias Bynens
96	 * @link https://github.com/mathiasbynens/CSS.escape
97	 */
98	var escapeCharacters = function (id) {
99
100		// Remove leading hash
101		if (id.charAt(0) === '#') {
102			id = id.substr(1);
103		}
104
105		var string = String(id);
106		var length = string.length;
107		var index = -1;
108		var codeUnit;
109		var result = '';
110		var firstCodeUnit = string.charCodeAt(0);
111		while (++index < length) {
112			codeUnit = string.charCodeAt(index);
113			// Note: there’s no need to special-case astral symbols, surrogate
114			// pairs, or lone surrogates.
115
116			// If the character is NULL (U+0000), then throw an
117			// `InvalidCharacterError` exception and terminate these steps.
118			if (codeUnit === 0x0000) {
119				throw new InvalidCharacterError(
120					'Invalid character: the input contains U+0000.'
121				);
122			}
123
124			if (
125				// If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
126				// U+007F, […]
127				(codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||
128				// If the character is the first character and is in the range [0-9]
129				// (U+0030 to U+0039), […]
130				(index === 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
131				// If the character is the second character and is in the range [0-9]
132				// (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
133				(
134					index === 1 &&
135					codeUnit >= 0x0030 && codeUnit <= 0x0039 &&
136					firstCodeUnit === 0x002D
137				)
138			) {
139				// http://dev.w3.org/csswg/cssom/#escape-a-character-as-code-point
140				result += '\\' + codeUnit.toString(16) + ' ';
141				continue;
142			}
143
144			// If the character is not handled by one of the above rules and is
145			// greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
146			// is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
147			// U+005A), or [a-z] (U+0061 to U+007A), […]
148			if (
149				codeUnit >= 0x0080 ||
150				codeUnit === 0x002D ||
151				codeUnit === 0x005F ||
152				codeUnit >= 0x0030 && codeUnit <= 0x0039 ||
153				codeUnit >= 0x0041 && codeUnit <= 0x005A ||
154				codeUnit >= 0x0061 && codeUnit <= 0x007A
155			) {
156				// the character itself
157				result += string.charAt(index);
158				continue;
159			}
160
161			// Otherwise, the escaped character.
162			// http://dev.w3.org/csswg/cssom/#escape-a-character
163			result += '\\' + string.charAt(index);
164
165		}
166
167		return '#' + result;
168
169	};
170
171	/**
172	 * Calculate the easing pattern
173	 * @link https://gist.github.com/gre/1650294
174	 * @param {String} type Easing pattern
175	 * @param {Number} time Time animation should take to complete
176	 * @returns {Number}
177	 */
178	var easingPattern = function (settings, time) {
179		var pattern;
180
181		// Default Easing Patterns
182		if (settings.easing === 'easeInQuad') pattern = time * time; // accelerating from zero velocity
183		if (settings.easing === 'easeOutQuad') pattern = time * (2 - time); // decelerating to zero velocity
184		if (settings.easing === 'easeInOutQuad') pattern = time < 0.5 ? 2 * time * time : -1 + (4 - 2 * t
vendor: 4,600 bytes, lines 184-313
184ime) * time; // acceleration until halfway, then deceleration
185		if (settings.easing === 'easeInCubic') pattern = time * time * time; // accelerating from zero velocity
186		if (settings.easing === 'easeOutCubic') pattern = (--time) * time * time + 1; // decelerating to zero velocity
187		if (settings.easing === 'easeInOutCubic') pattern = time < 0.5 ? 4 * time * time * time : (time - 1) * (2 * time - 2) * (2 * time - 2) + 1; // acceleration until halfway, then deceleration
188		if (settings.easing === 'easeInQuart') pattern = time * time * time * time; // accelerating from zero velocity
189		if (settings.easing === 'easeOutQuart') pattern = 1 - (--time) * time * time * time; // decelerating to zero velocity
190		if (settings.easing === 'easeInOutQuart') pattern = time < 0.5 ? 8 * time * time * time * time : 1 - 8 * (--time) * time * time * time; // acceleration until halfway, then deceleration
191		if (settings.easing === 'easeInQuint') pattern = time * time * time * time * time; // accelerating from zero velocity
192		if (settings.easing === 'easeOutQuint') pattern = 1 + (--time) * time * time * time * time; // decelerating to zero velocity
193		if (settings.easing === 'easeInOutQuint') pattern = time < 0.5 ? 16 * time * time * time * time * time : 1 + 16 * (--time) * time * time * time * time; // acceleration until halfway, then deceleration
194
195		// Custom Easing Patterns
196		if (!!settings.customEasing) pattern = settings.customEasing(time);
197
198		return pattern || time; // no easing, no acceleration
199	};
200
201	/**
202	 * Determine the document's height
203	 * @returns {Number}
204	 */
205	var getDocumentHeight = function () {
206		return Math.max(
207			document.body.scrollHeight, document.documentElement.scrollHeight,
208			document.body.offsetHeight, document.documentElement.offsetHeight,
209			document.body.clientHeight, document.documentElement.clientHeight
210		);
211	};
212
213	/**
214	 * Calculate how far to scroll
215	 * @param {Element} anchor The anchor element to scroll to
216	 * @param {Number} headerHeight Height of a fixed header, if any
217	 * @param {Number} offset Number of pixels by which to offset scroll
218	 * @returns {Number}
219	 */
220	var getEndLocation = function (anchor, headerHeight, offset) {
221		var location = 0;
222		if (anchor.offsetParent) {
223			do {
224				location += anchor.offsetTop;
225				anchor = anchor.offsetParent;
226			} while (anchor);
227		}
228		location = Math.max(location - headerHeight - offset, 0);
229		return location;
230	};
231
232	/**
233	 * Get the height of the fixed header
234	 * @param  {Node}   header The header
235	 * @return {Number}        The height of the header
236	 */
237	var getHeaderHeight = function (header) {
238		return !header ? 0 : (getHeight(header) + header.offsetTop);
239	};
240
241	/**
242	 * Bring the anchored element into focus
243	 * @param {Node}     anchor      The anchor element
244	 * @param {Number}   endLocation The end location to scroll to
245	 * @param {Boolean}  isNum       If true, scroll is to a position rather than an element
246	 */
247	var adjustFocus = function (anchor, endLocation, isNum) {
248
249		// Don't run if scrolling to a number on the page
250		if (isNum) return;
251
252		// Otherwise, bring anchor element into focus
253		anchor.focus();
254		if (document.activeElement.id !== anchor.id) {
255			anchor.setAttribute('tabindex', '-1');
256			anchor.focus();
257			anchor.style.outline = 'none';
258		}
259		window.scrollTo(0 , endLocation);
260
261	};
262
263	/**
264	 * Check to see if user prefers reduced motion
265	 * @param  {Object} settings Script settings
266	 */
267	var reduceMotion = function (settings) {
268		if ('matchMedia' in window && window.matchMedia('(prefers-reduced-motion)').matches) {
269			return true;
270		}
271		return false;
272	};
273
274
275	//
276	// SmoothScroll Constructor
277	//
278
279	var SmoothScroll = function (selector, options) {
280
281		//
282		// Variables
283		//
284
285		var smoothScroll = {}; // Object for public APIs
286		var settings, anchor, toggle, fixedHeader, headerHeight, eventTimeout, animationInterval;
287
288
289		//
290		// Methods
291		//
292
293		/**
294		 * Cancel a scroll-in-progress
295		 */
296		smoothScroll.cancelScroll = function () {
297			// clearInterval(animationInterval);
298			cancelAnimationFrame(animationInterval);
299		};
300
301		/**
302		 * Start/stop the scrolling animation
303		 * @param {Node|Number} anchor  The element or position to scroll to
304		 * @param {Element}     toggle  The element that toggled the scroll event
305		 * @param {Object}      options
306		 */
307		smoothScroll.animateScroll = function (anchor, toggle, options) {
308
309			// Local settings
310			var animateSettings = extend(settings || defaults, options || {}); // Merge user options with defaults
311
312			// Selectors and variables
313			var isNum = Object.prototype.toString.call(anchor) === '[object Number]' ? true : false;
314			var anchorElem = isNum || !anchor.tagName ? null : anchor;
315			if (!isNum && !anchorElem) return;
316			var startLocation = window.pageYOffset; // Current location on the page
317			if (animateSettings.header && !fixedHeader) {
318				// Get the fixed header if not already set
319				fixedHeader = document.querySelector( animateSettings.header );
320			}
321			if (!headerHeight) {
322				// Get the height of a fixed header if one exists and not already set
323				headerHeight = getHeaderHeight(fixedHeader);
324			}
325			var endLocation = isNum ? anchor : getEndLocation(anchorElem, headerHeight, parseInt((typeof animateSettings.offset === 'function' ? animateSettings.offset() : animateSettings.offset), 10)); // Location to scroll to
326			var distance = endLocation - startLocation; // distance to travel
327			var documentHeight = getDocumentHeight();
328			var timeLapsed = 0;
329			var start, percentage, position;
330
331			/**
332			 * Stop the scroll animation when it reaches its target (or the bottom/top of page)
333			 * @param {Number} position Current position on the page
334			 * @param {Number} endLocation Scroll to location
335			 * @param {Number} animationInterval How much to scroll on this loop
336			 */
337			var stopAnimateScroll = function (position, endLocation) {
338
339				// Get the current location
340				var currentLocation = window.pageYOffset;
341
342				// Check if the end location has been reached yet (or we've hit the end of the document)
343				if ( position == endLocation || currentLocation == endLocation || ((startLocation < endLocation && window.innerHeight + currentLocation) >= documentHeight )) {
344
345					// Clear the animation timer
346					smoothScroll.cancelScroll();
347
348					// Bring the anchored element into focus
349					adjustFocus(anchor, endLocation, isNum);
350
351					// Run callback after animation complete
352					animateSettings.after(anchor, toggle);
353
354					// Reset start
355					start = null;
356
357					return true;
358
359				}
360			};
361
362			/**
363			 * Loop scrolling animation
364			 */
365			var loopAnimateScroll = function (timestamp) {
366				if (!start) { start = timestamp; }
367				timeLapsed += timestamp - start;
368				percentage = (timeLapsed / parseInt(animateSettings.speed, 10));
369				percentage = (percentage > 1) ? 1 : percentage;
370				position = startLocation + (distance * easingPattern(animateSettings, percentage));
371				window.scrollTo(0, Math.floor(position));
372				if (!stopAnimateScroll(position, endLocation)) {
373					window.requestAnimationFrame(loopAnimateScroll);
374					start = timestamp;
375				}
376			};
377
378			/**
379			 * Reset position to fix weird iOS bug
380			 * @link https://github.com/cferdinandi/smooth-scroll/issues/45
381			 */
382			if (window.pageYOffset === 0) {
383				window.scrollTo( 0, 0 );
384			}
385
386			// Run callback before animation starts
387			animateSettings.before(anchor, toggle);
388
389			// Start scrolling animation
390			smoothScroll.cancelScroll();
391			window.requestAnimationFrame(loopAnimateScroll);
392
393
394		};
395
396		/**
397		 * Handle has change event
398		 */
399		var hashChangeHandler = function (event) {
400
401			// Only run if there's an anchor element to scroll to
402			if (!anchor) return;
403
404			// Reset the anchor element's ID
405			anchor.id = anchor.getAttribute('data-scroll-id');
406
407			// Scroll to the anchored content
408			smoothScroll.animateScroll(anchor, toggle);
409
410			// Reset anchor and toggle
411			anchor = null;
412			toggle = null;
413
414		};
415
416		/**
417		 * If smooth scroll element clicked, animate scroll
418		 */
419		var clickHandler = function (event) {
420
421			// Don't run if the user prefers reduced motion
422			if (reduceMotion(settings)) return;
423
424			// Don't run if right-click or command/control + click
425			if (event.button !== 0 || event.metaKey || event.ctrlKey) return;
426
427			// Check if a smooth scroll link was clicked
428			toggle = event.target.closest(selector);
429			if (!toggle || toggle.tagName.toLowerCase() !== 'a' || event.target.closest(settings.ignore)) return;
430
431			// Only run if link is an anchor and points to the current page
432			if (toggle.hostname !== window.location.hostname || toggle.pathname !== window.location.pathname || !/#/.test(toggle.href)) return;
433
434			// Get the sanitized hash
435			var hash;
436			try {
437				hash = escapeCharacters(decodeURIComponent(toggle.hash));
438			} catch(e) {
439				hash = escapeCharacters(toggle.hash);
440			}
441
442			// If the hash is empty, scroll to the top of the page
443			if (hash === '#') {
444
445				// Prevent default link behavior
446				event.preventDefault();
447
448				// Set the anchored element
449				anchor = document.body;
450
451				// Save or create the ID as a data attribute and remove it (prevents scroll jump)
452				var id = anchor.id ? anchor.id : 'smooth-scroll-top';
453				anchor.setAttribute('data-scroll-id', id);
454				anchor.id = '';
455
456				// If no hash change event will happen, fire manually
457				// Otherwise, update the hash
458				if (window.location.hash.substring(1) === id) {
459					hashChangeHandler();
460				} else {
461					window.location.hash = id;
462				}
463
464				return;
465
466			}
467
468			// Get the anchored element
469			anchor = document.querySelector(hash);
470
471			// If anchored element exists, save the ID as a data attribute and remove it (prevents scroll jump)
472			if (!anchor) return;
473			anchor.setAttribute('data-scroll-id', anchor.id);
474			anchor.id = '';
475
476			// If no hash change event will happen, fire manually
477			if (toggle.hash === window.location.hash) {
478				event.preventDefault();
479				hashChangeHandler();
480			}
481
482		};
483
484		/**
485		 * On window scroll and resize, only run events at a rate of 15fps for better performance
486		 */
487		var resizeThrottler = function (event) {
488			if (!eventTimeout) {
489				eventTimeout = setTimeout(function() {
490					eventTimeout = null; // Reset timeout
491					headerHeight = getHeaderHeight(fixedHeader); // Get the height of a fixed header if one exists
492				}, 66);
493			}
494		};
495
496		/**
497		 * Destroy the current initialization.
498		 */
499		smoothScroll.destroy = function () {
500
501			// If plugin isn't already initialized, stop
502			if (!settings) return;
503
504			// Remove event listeners
505			document.removeEventListener('click', clickHandler, false);
506			window.removeEventListener('resize', resizeThrottler, false);
507
508			// Cancel any scrolls-in-progress
509			smoothScroll.cancelScroll();
510
511			// Reset variables
512			settings = null;
513			anchor = null;
514			toggle = null;
515			fixedHeader = null;
516			headerHeight = null;
517			eventTimeout = null;
518			animationInterval = null;
519		};
520
521		/**
522		 * Initialize Smooth Scroll
523		 * @param {Object} options User settings
524		 */
525		smoothScroll.init = function (options) {
526
527			// feature test
528			if (!supports) return;
529
530			// Destroy any existing initializations
531			smoothScroll.destroy();
532
533			// Selectors and variables
534			settings = extend(defaults, options || {}); // Merge user options with defaults
535			fixedHeader = settings.header ? document.querySelector(settings.header) : null; // Get the fixed header
536			headerHeight = getHeaderHeight(fixedHeader);
537
538			// When a toggle is clicked, run the click handler
539			document.addEventListener('click', clickHandler, false);
540
541			// Listen for hash changes
542			window.addEventListener('hashchange', hashChangeHandler, false);
543
544			// If window is resized and there's a fixed header, recalculate its size
545			if (fixedHeader) {
546				window.addEventListener('resize', resizeThrottler, false);
547			}
548
549		};
550
551
552		//
553		// Initialize plugin
554		//
555
556		smoothScroll.init(options);
557
558
559		//
560		// Public APIs
561		//
562
563		return smoothScroll;
564
565	};
566
567	return SmoothScroll;
568
569});

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.