PageSourceSearch

https://www.ehsrestoration.com/wp-content/themes/specular/js/smoothscroll.js

js ehsrestoration.com collected 2026-09-30 11:07:07 UTC 21,373 bytes, 788 lines download raw bytes

vendor: 9,405 bytes, lines 1-370
1//
2// SmoothScroll for websites v1.4.9 (Balazs Galambosi)
3// http://www.smoothscroll.net/
4//
5// Licensed under the terms of the MIT license.
6//
7// You may use it in your theme if you credit me. 
8// It is also free to use on any individual website.
9//
10// Exception:
11// The only restriction is to not publish any  
12// extension for browsers or native application
13// without getting a written permission first.
14//
15
16(function () {
17  
18	// Scroll Variables (tweakable)
19	var defaultOptions = {
20	
21		// Scrolling Core
22		frameRate        : 150, // [Hz]
23		animationTime    : 400, // [ms]
24		stepSize         : 100, // [px]
25	
26		// Pulse (less tweakable)
27		// ratio of "tail" to "acceleration"
28		pulseAlgorithm   : true,
29		pulseScale       : 4,
30		pulseNormalize   : 1,
31	
32		// Acceleration
33		accelerationDelta : 50,  // 50
34		accelerationMax   : 3,   // 3
35	
36		// Keyboard Settings
37		keyboardSupport   : true,  // option
38		arrowScroll       : 50,    // [px]
39	
40		// Other
41		fixedBackground   : true, 
42		excluded          : ''    
43	};
44	
45	var options = defaultOptions;
46	
47	
48	// Other Variables
49	var isExcluded = false;
50	var isFrame = false;
51	var direction = { x: 0, y: 0 };
52	var initDone  = false;
53	var root = document.documentElement;
54	var activeElement;
55	var observer;
56	var refreshSize;
57	var deltaBuffer = [];
58	var deltaBufferTimer;
59	var isMac = /^Mac/.test(navigator.platform);
60	
61	var key = { left: 37, up: 38, right: 39, down: 40, spacebar: 32, 
62				pageup: 33, pagedown: 34, end: 35, home: 36 };
63	var arrowKeys = { 37: 1, 38: 1, 39: 1, 40: 1 };
64	
65	/***********************************************
66	 * INITIALIZE
67	 ***********************************************/
68	
69	/**
70	 * Tests if smooth scrolling is allowed. Shuts down everything if not.
71	 */
72	function initTest() {
73		if (options.keyboardSupport) {
74			addEvent('keydown', keydown);
75		}
76	}
77	
78	/**
79	 * Sets up scrolls array, determines if frames are involved.
80	 */
81	function init() {
82	  
83		if (initDone || !document.body) return;
84	
85		initDone = true;
86	
87		var body = document.body;
88		var html = document.documentElement;
89		var windowHeight = window.innerHeight; 
90		var scrollHeight = body.scrollHeight;
91		
92		// check compat mode for root element
93		root = (document.compatMode.indexOf('CSS') >= 0) ? html : body;
94		activeElement = body;
95		
96		initTest();
97	
98		// Checks if this script is running in a frame
99		if (top != self) {
100			isFrame = true;
101		}
102	
103		/**
104		 * Safari 10 fixed it, Chrome fixed it in v45:
105		 * This fixes a bug where the areas left and right to 
106		 * the content does not trigger the onmousewheel event
107		 * on some pages. e.g.: html, body { height: 100% }
108		 */
109		else if (isOldSafari &&
110				 scrollHeight > windowHeight &&
111				(body.offsetHeight <= windowHeight || 
112				 html.offsetHeight <= windowHeight)) {
113	
114			var fullPageElem = document.createElement('div');
115			fullPageElem.style.cssText = 'position:absolute; z-index:-10000; ' +
116										 'top:0; left:0; right:0; height:' + 
117										  root.scrollHeight + 'px';
118			document.body.appendChild(fullPageElem);
119			
120			// DOM changed (throttled) to fix height
121			var pendingRefresh;
122			refreshSize = function () {
123				if (pendingRefresh) return; // could also be: clearTimeout(pendingRefresh);
124				pendingRefresh = setTimeout(function () {
125					if (isExcluded) return; // could be running after cleanup
126					fullPageElem.style.height = '0';
127					fullPageElem.style.height = root.scrollHeight + 'px';
128					pendingRefresh = null;
129				}, 500); // act rarely to stay fast
130			};
131	  
132			setTimeout(refreshSize, 10);
133	
134			addEvent('resize', refreshSize);
135	
136			// TODO: attributeFilter?
137			var config = {
138				attributes: true, 
139				childList: true, 
140				characterData: false 
141				// subtree: true
142			};
143	
144			observer = new MutationObserver(refreshSize);
145			observer.observe(body, config);
146	
147			if (root.offsetHeight <= windowHeight) {
148				var clearfix = document.createElement('div');   
149				clearfix.style.clear = 'both';
150				body.appendChild(clearfix);
151			}
152		}
153	
154		// disable fixed background
155		if (!options.fixedBackground && !isExcluded) {
156			body.style.backgroundAttachment = 'scroll';
157			html.style.backgroundAttachment = 'scroll';
158		}
159	}
160	
161	/**
162	 * Removes event listeners and other traces left on the page.
163	 */
164	function cleanup() {
165		observer && observer.disconnect();
166		removeEvent(wheelEvent, wheel);
167		removeEvent('mousedown', mousedown);
168		removeEvent('keydown', keydown);
169		removeEvent('resize', refreshSize);
170		removeEvent('load', init);
171	}
172	
173	
174	/************************************************
175	 * SCROLLING 
176	 ************************************************/
177	 
178	var que = [];
179	var pending = false;
180	var lastScroll = Date.now();
181	
182	/**
183	 * Pushes scroll actions to the scrolling queue.
184	 */
185	function scrollArray(elem, left, top) {
186		
187		directionCheck(left, top);
188	
189		if (options.accelerationMax != 1) {
190			var now = Date.now();
191			var elapsed = now - lastScroll;
192			if (elapsed < options.accelerationDelta) {
193				var factor = (1 + (50 / elapsed)) / 2;
194				if (factor > 1) {
195					factor = Math.min(factor, options.accelerationMax);
196					left *= factor;
197					top  *= factor;
198				}
199			}
200			lastScroll = Date.now();
201		}          
202		
203		// push a scroll command
204		que.push({
205			x: left, 
206			y: top, 
207			lastX: (left < 0) ? 0.99 : -0.99,
208			lastY: (top  < 0) ? 0.99 : -0.99, 
209			start: Date.now()
210		});
211			
212		// don't act if there's a pending queue
213		if (pending) {
214			return;
215		}  
216	
217		var scrollRoot = getScrollRoot();
218		var isWindowScroll = (elem === scrollRoot || elem === document.body);
219		
220		// if we haven't already fixed the behavior, 
221		// and it needs fixing for this sesh
222		if (elem.$scrollBehavior == null && isScrollBehaviorSmooth(elem)) {
223			elem.$scrollBehavior = elem.style.scrollBehavior;
224			elem.style.scrollBehavior = 'auto';
225		}
226	
227		var step = function (time) {
228			
229			var now = Date.now();
230			var scrollX = 0;
231			var scrollY = 0; 
232		
233			for (var i = 0; i < que.length; i++) {
234				
235				var item = que[i];
236				var elapsed  = now - item.start;
237				var finished = (elapsed >= options.animationTime);
238				
239				// scroll position: [0, 1]
240				var position = (finished) ? 1 : elapsed / options.animationTime;
241				
242				// easing [optional]
243				if (options.pulseAlgorithm) {
244					position = pulse(position);
245				}
246				
247				// only need the difference
248				var x = (item.x * position - item.lastX) >> 0;
249				var y = (item.y * position - item.lastY) >> 0;
250				
251				// add this to the total scrolling
252				scrollX += x;
253				scrollY += y;            
254				
255				// update last values
256				item.lastX += x;
257				item.lastY += y;
258			
259				// delete and step back if it's over
260				if (finished) {
261					que.splice(i, 1); i--;
262				}           
263			}
264	
265			// scroll left and top
266			if (isWindowScroll) {
267				window.scrollBy(scrollX, scrollY);
268			} 
269			else {
270				if (scrollX) elem.scrollLeft += scrollX;
271				if (scrollY) elem.scrollTop  += scrollY;                    
272			}
273			
274			// clean up if there's nothing left to do
275			if (!left && !top) {
276				que = [];
277			}
278			
279			if (que.length) { 
280				requestFrame(step, elem, (1000 / options.frameRate + 1)); 
281			} else { 
282				pending = false;
283				// restore default behavior at the end of scrolling sesh
284				if (elem.$scrollBehavior != null) {
285					elem.style.scrollBehavior = elem.$scrollBehavior;
286					elem.$scrollBehavior = null;
287				}
288			}
289		};
290		
291		// start a new queue of actions
292		requestFrame(step, elem, 0);
293		pending = true;
294	}
295	
296	
297	/***********************************************
298	 * EVENTS
299	 ***********************************************/
300	
301	/**
302	 * Mouse wheel handler.
303	 * @param {Object} event
304	 */
305	function wheel(event) {
306	
307		if (!initDone) {
308			init();
309		}
310		
311		var target = event.target;
312	
313		// leave early if default action is prevented   
314		// or it's a zooming event with CTRL 
315		if (event.defaultPrevented || event.ctrlKey) {
316			return true;
317		}
318		
319		// leave embedded content alone (flash & pdf)
320		if (isNodeName(activeElement, 'embed') || 
321		   (isNodeName(target, 'embed') && /\.pdf/i.test(target.src)) ||
322			isNodeName(activeElement, 'object') ||
323			target.shadowRoot) {
324			return true;
325		}
326	
327		var deltaX = -event.wheelDeltaX || event.deltaX || 0;
328		var deltaY = -event.wheelDeltaY || event.deltaY || 0;
329		
330		if (isMac) {
331			if (event.wheelDeltaX && isDivisible(event.wheelDeltaX, 120)) {
332				deltaX = -120 * (event.wheelDeltaX / Math.abs(event.wheelDeltaX));
333			}
334			if (event.wheelDeltaY && isDivisible(event.wheelDeltaY, 120)) {
335				deltaY = -120 * (event.wheelDeltaY / Math.abs(event.wheelDeltaY));
336			}
337		}
338		
339		// use wheelDelta if deltaX/Y is not available
340		if (!deltaX && !deltaY) {
341			deltaY = -event.wheelDelta || 0;
342		}
343	
344		// line based scrolling (Firefox mostly)
345		if (event.deltaMode === 1) {
346			deltaX *= 40;
347			deltaY *= 40;
348		}
349	
350		var overflowing = overflowingAncestor(target);
351	
352		// nothing to do if there's no element that's scrollable
353		if (!overflowing) {
354			// except Chrome iframes seem to eat wheel events, which we need to 
355			// propagate up, if the iframe has nothing overflowing to scroll
356			if (isFrame && isChrome)  {
357				// change target to iframe element itself for the parent frame
358				Object.defineProperty(event, "target", {value: window.frameElement});
359				return parent.wheel(event);
360			}
361			return true;
362		}
363		
364		// check if it's a touchpad scroll that should be ignored
365		if (isTouchpad(deltaY)) {
366			return true;
367		}
368	
369		// scale by step size
370		// delta is 120 most of the time
371		// synaptics seems to send 1 sometimes
372		if (Math.abs(deltaX) > 1.2) {
373			deltaX *= options.stepSize / 120;
374		}
375		if (Math.abs(deltaY) > 1.2) {
376			deltaY *= options.stepSize / 120;
377		}
378		
379		scrollArray(overflowing, deltaX, deltaY);
380		event.preventDefault();
381		scheduleClearCache();
382	}
383	
384	/**
385	 * Keydown event handler.
386	 * @param {Object} event
387	 */
388	function keydown(event) {
389	
390		var target   = event.target;
391		var modifier = event.ctrlKey || event.altKey || event.metaKey || 
392					  (event.shiftKey && event.keyCode !== key.spacebar);
393		
394		// our own tracked active element could've been removed from the DOM
395		if (!document.body.contains(activeElement)) {
396			activeElement = document.activeElement;
397		}
398	
399		// do nothing if user is editing text
400		// or using a modifier key (except shift)
401		// or in a dropdown
402		// or inside interactive elements
403		var inputNodeNames = /^(textarea|select|embed|object)$/i;
404		var buttonTypes = /^(button|submit|radio|checkbox|file|color|image)$/i;
405		if ( event.defaultPrevented ||
406			 inputNodeNames.test(target.nodeName) ||
407			 isNodeName(target, 'input') && !buttonTypes.test(target.type) ||
408			 isNodeName(activeElement, 'video') ||
409			 isInsideYoutubeVideo(event) ||
410			 target.isContentEditable || 
411			 modifier ) {
412		  return true;
413		}
414	
415		// [spacebar] should trigger button press, leave it alone
416		if ((isNodeName(target, 'button') ||
417			 isNodeName(target, 'input') && buttonTypes.test(target.type)) &&
418			event.keyCode === key.spacebar) {
419		  return true;
420		}
421	
422		// [arrwow keys] on radio buttons should be left alone
423		if (isNodeName(target, 'input') && target.type == 'radio' &&
424			arrowKeys[event.keyCode])  {
425		  return true;
426		}
427		
428		var shift, x = 0, y = 0;
429		var overflowing = overflowingAncestor(activeElement);
430	
431		if (!overflowing) {
432			// Chrome iframes seem to eat key events, which we need to 
433			// propagate up, if the iframe has nothing overflowing to scroll
434			return (isFrame && isChrome) ? parent.keydown(event) : true;
435		}
436	
437		var clientHeight = overflowing.clientHeight; 
438	
439		if (overflowing == document.body) {
440			clientHeight = window.innerHeight;
441		}
442	
443		switch (event.keyCode) {
444			case key.up:
445				y = -options.arrowScroll;
446				break;
447			case key.down:
448				y = options.arrowScroll;
449				break;         
450			case key.spacebar: // (+ shift)
451				shift = event.shiftKey ? 1 : -1;
452				y = -shift * clientHeight * 0.9;
453				break;
454			case key.pageup:
455				y = -clientHeight * 0.9;
456				break;
457			case key.pagedown:
458				y = clientHeight * 0.9;
459				break;
460			case key.home:
461				if (overflowing == document.body && document.scrollingElement)
462					overflowing = document.scrollingElement;
463				y = -overflowing.scrollTop;
464				break;
465			case key.end:
466				var scroll = overflowing.scrollHeight - overflowing.scrollTop;
467				var scrollRemaining = scroll - clientHeight;
468				y = (scrollRemaining > 0) ? scrollRemaining + 10 : 0;
469				break;
470			case key.left:
471				x = -options.arrowScroll;
472				break;
473			case key.right:
474				x = options.arrowScroll;
475				break;            
476			default:
477				return true; // a key we don't care about
478		}
479	
480		scrollArray(overflowing, x, y);
481		event.preventDefault();
482		scheduleClearCache();
483	}
484	
485	/**
486	 * Mousedown event only for updating activeElement
487	 */
488	function mousedown(event) {
489		activeElement = event.target;
490	}
491	
492	
493	/***********************************************
494	 * OVERFLOW
495	 ***********************************************/
496	
497	var uniqueID = (function () {
498		var i = 0;
499		return function (el) {
500			return el.uniqueID || (el.uniqueID = i++);
501		};
502	})();
503	
504	var cacheX = {}; // cleared out after a scrolling session
505	var cacheY = {}; // cleared out after a scrolling session
506	var clearCacheTimer;
507	var smoothBehaviorForElement = {};
508	
509	//setInterval(function () { cache = {}; }, 10 * 1000);
510	
511	function scheduleClearCache() {
512		clearTimeout(clearCacheTimer);
513		clearCacheTimer = setInterval(function () { 
514			cacheX = cacheY = smoothBehaviorForElement = {}; 
515		}, 1*1000);
516	}
517	
518	function setCache(elems, overflowing, x) {
519		var cache = x ? cacheX : cacheY;
520		for (var i = elems.length; i--;)
521			cache[uniqueID(elems[i])] = overflowing;
522		return overflowing;
523	}
524	
525	function getCache(el, x) {
526		return (x ? cacheX : cacheY)[uniqueID(el)];
527	}
528	
529	//  (body)                (root)
530	//         | hidden | visible | scroll |  auto  |
531	// hidden  |   no   |    no   |   YES  |   YES  |
532	// visible |   no   |   YES   |   YES  |   YES  |
533	// scroll  |   no   |   YES   |   YES  |   YES  |
534	// auto    |   no   |   YES   |   YES  |   YES  |
535	
536	function overflowingAncestor(el) {
537		var elems = [];
538		var body = document.body;
539		var rootScrollHeight = root.scrollHeight;
540		do {
541			var cached = getCache(el, false);
542			if (cached) {
543				return setCache(elems, cached);
544			}
545			elems.push(el);
546			if (rootScrollHeight === el.scrollHeight) {
547				var topOverflowsNotHidden = overflowNotHidden(root) && overflowNotHidden(body);
548				var isOverflowCSS = topOverflowsNotHidden || overflowAutoOrScroll(root);
549				if (isFrame && isContentOverflowing(root) || 
550				   !isFrame && isOverflowCSS) {
551					return setCache(elems, getScrollRoot()); 
552				}
553			} else if (isContentOverflowing(el) && overflowAutoOrScroll(el)) {
554				return setCache(elems, el);
555			}
556		} while ((el = el.parentElement));
557	}
558	
559	function isContentOverflowing(el) {
560		return (el.clientHeight + 10 < el.scrollHeight);
561	}
562	
563	// typically for <body> and <html>
564	function overflowNotHidden(el) {
565		var overflow = getComputedStyle(el, '').getPropertyValue('overflow-y');
566		return (overflow !== 'hidden');
567	}
568	
569	// for all other elements
570	function overflowAutoOrScroll(el) {
571		var overflow = getComputedStyle(el, '').getPropertyValue('overflow-y');
572		return (overflow === 'scroll' || overflow === 'auto');
573	}
574	
575	// for all other elements
576	function isScrollBehaviorSmooth(el) {
577		var id = uniqueID(el);
578		if (smoothBehaviorForElement[id] == null) {
579			var scrollBehavior = getComputedStyle(el, '')['scroll-behavior'];
580			smoothBehaviorForElement[id] = ('smooth' == scrollBehavior);
581		}
582		return smoothBehaviorForElement[id];
583	}
584	
585	
586	/***********************************************
587	 * HELPERS
588	 ***********************************************/
589	
590	function addEvent(type, fn, arg) {
591		window.addEventListener(type, fn, arg || false);
592	}
593	
594	function removeEvent(type, fn, arg) {
595		window.removeEventListener(type, fn, arg || false);  
596	}
597	
598	function isNodeName(el, tag) {
vendor: 5,562 bytes, lines 599-788
599		return el && (el.nodeName||'').toLowerCase() === tag.toLowerCase();
600	}
601	
602	function directionCheck(x, y) {
603		x = (x > 0) ? 1 : -1;
604		y = (y > 0) ? 1 : -1;
605		if (direction.x !== x || direction.y !== y) {
606			direction.x = x;
607			direction.y = y;
608			que = [];
609			lastScroll = 0;
610		}
611	}
612	
613	if (window.localStorage && localStorage.SS_deltaBuffer) {
614		try { // #46 Safari throws in private browsing for localStorage 
615			deltaBuffer = localStorage.SS_deltaBuffer.split(',');
616		} catch (e) { } 
617	}
618	
619	function isTouchpad(deltaY) {
620		if (!deltaY) return;
621		if (!deltaBuffer.length) {
622			deltaBuffer = [deltaY, deltaY, deltaY];
623		}
624		deltaY = Math.abs(deltaY);
625		deltaBuffer.push(deltaY);
626		deltaBuffer.shift();
627		clearTimeout(deltaBufferTimer);
628		deltaBufferTimer = setTimeout(function () {
629			try { // #46 Safari throws in private browsing for localStorage
630				localStorage.SS_deltaBuffer = deltaBuffer.join(',');
631			} catch (e) { }  
632		}, 1000);
633		var dpiScaledWheelDelta = deltaY > 120 && allDeltasDivisableBy(deltaY); // win64 
634		return !allDeltasDivisableBy(120) && !allDeltasDivisableBy(100) && !dpiScaledWheelDelta;
635	} 
636	
637	function isDivisible(n, divisor) {
638		return (Math.floor(n / divisor) == n / divisor);
639	}
640	
641	function allDeltasDivisableBy(divisor) {
642		return (isDivisible(deltaBuffer[0], divisor) &&
643				isDivisible(deltaBuffer[1], divisor) &&
644				isDivisible(deltaBuffer[2], divisor));
645	}
646	
647	function isInsideYoutubeVideo(event) {
648		var elem = event.target;
649		var isControl = false;
650		if (document.URL.indexOf ('www.youtube.com/watch') != -1) {
651			do {
652				isControl = (elem.classList && 
653							 elem.classList.contains('html5-video-controls'));
654				if (isControl) break;
655			} while ((elem = elem.parentNode));
656		}
657		return isControl;
658	}
659	
660	var requestFrame = (function () {
661		  return (window.requestAnimationFrame       || 
662				  window.webkitRequestAnimationFrame || 
663				  window.mozRequestAnimationFrame    ||
664				  function (callback, element, delay) {
665					 window.setTimeout(callback, delay || (1000/60));
666				 });
667	})();
668	
669	var MutationObserver = (window.MutationObserver || 
670							window.WebKitMutationObserver ||
671							window.MozMutationObserver);  
672	
673	var getScrollRoot = (function() {
674	  var SCROLL_ROOT = document.scrollingElement;
675	  return function() {
676		if (!SCROLL_ROOT) {
677		  var dummy = document.createElement('div');
678		  dummy.style.cssText = 'height:10000px;width:1px;';
679		  document.body.appendChild(dummy);
680		  var bodyScrollTop  = document.body.scrollTop;
681		  var docElScrollTop = document.documentElement.scrollTop;
682		  window.scrollBy(0, 3);
683		  if (document.body.scrollTop != bodyScrollTop)
684			(SCROLL_ROOT = document.body);
685		  else 
686			(SCROLL_ROOT = document.documentElement);
687		  window.scrollBy(0, -3);
688		  document.body.removeChild(dummy);
689		}
690		return SCROLL_ROOT;
691	  };
692	})();
693	
694	
695	/***********************************************
696	 * PULSE (by Michael Herf)
697	 ***********************************************/
698	 
699	/**
700	 * Viscous fluid with a pulse for part and decay for the rest.
701	 * - Applies a fixed force over an interval (a damped acceleration), and
702	 * - Lets the exponential bleed away the velocity over a longer interval
703	 * - Michael Herf, http://stereopsis.com/stopping/
704	 */
705	function pulse_(x) {
706		var val, start, expx;
707		// test
708		x = x * options.pulseScale;
709		if (x < 1) { // acceleartion
710			val = x - (1 - Math.exp(-x));
711		} else {     // tail
712			// the previous animation ended here:
713			start = Math.exp(-1);
714			// simple viscous drag
715			x -= 1;
716			expx = 1 - Math.exp(-x);
717			val = start + (expx * (1 - start));
718		}
719		return val * options.pulseNormalize;
720	}
721	
722	function pulse(x) {
723		if (x >= 1) return 1;
724		if (x <= 0) return 0;
725	
726		if (options.pulseNormalize == 1) {
727			options.pulseNormalize /= pulse_(1);
728		}
729		return pulse_(x);
730	}
731	
732	
733	/***********************************************
734	 * FIRST RUN
735	 ***********************************************/
736	
737	var userAgent = window.navigator.userAgent;
738	var isEdge    = /Edge/.test(userAgent); // thank you MS
739	var isChrome  = /chrome/i.test(userAgent) && !isEdge; 
740	var isSafari  = /safari/i.test(userAgent) && !isEdge; 
741	var isMobile  = /mobile/i.test(userAgent);
742	var isIEWin7  = /Windows NT 6.1/i.test(userAgent) && /rv:11/i.test(userAgent);
743	var isOldSafari = isSafari && (/Version\/8/i.test(userAgent) || /Version\/9/i.test(userAgent));
744	var isEnabledForBrowser = (isChrome || isSafari || isIEWin7) && !isMobile;
745	
746	var supportsPassive = false;
747	try {
748	  window.addEventListener("test", null, Object.defineProperty({}, 'passive', {
749		get: function () {
750				supportsPassive = true;
751			} 
752		}));
753	} catch(e) {}
754	
755	var wheelOpt = supportsPassive ? { passive: false } : false;
756	var wheelEvent = 'onwheel' in document.createElement('div') ? 'wheel' : 'mousewheel'; 
757	
758	if (wheelEvent && isEnabledForBrowser) {
759		addEvent(wheelEvent, wheel, wheelOpt);
760		addEvent('mousedown', mousedown);
761		addEvent('load', init);
762	}
763	
764	
765	/***********************************************
766	 * PUBLIC INTERFACE
767	 ***********************************************/
768	
769	function SmoothScroll(optionsToSet) {
770		for (var key in optionsToSet)
771			if (defaultOptions.hasOwnProperty(key)) 
772				options[key] = optionsToSet[key];
773	}
774	SmoothScroll.destroy = cleanup;
775	
776	if (window.SmoothScrollOptions) // async API
777		SmoothScroll(window.SmoothScrollOptions);
778	
779	if (typeof define === 'function' && define.amd)
780		define(function() {
781			return SmoothScroll;
782		});
783	else if ('object' == typeof exports)
784		module.exports = SmoothScroll;
785	else
786		window.SmoothScroll = SmoothScroll;
787	
788	})();

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.