PageSourceSearch

https://mallen.es/wp-content/themes/Jade/js/smoothscroll.js?ver=7.1.2

js mallen.es collected 2026-10-02 13:40:07 UTC 10,905 bytes, 476 lines download raw bytes

1// SmoothScroll v1.2.1
2// Licensed under the terms of the MIT license.
3
4// People involved
5//  - Balazs Galambosi (maintainer)  
6//  - Patrick Brunner  (original idea)
7//  - Michael Herf     (Pulse Algorithm)
8//  - Justin Force     (Resurect)
9
10// Scroll Variables (tweakable)
11var framerate = 150; // [Hz]
12var animtime  = 400; // [px]
13var stepsize  = 80; // [px]
14
15// Pulse (less tweakable)
16// ratio of "tail" to "acceleration"
17var pulseAlgorithm = true;
18var pulseScale     = 8;
19var pulseNormalize = 1;
20
21// Acceleration
22var acceleration   = true;
23var accelDelta     = 10;  // 20
24var accelMax       = 1;   // 1
25
26// Keyboard Settings
27var keyboardsupport = true;  // option
28var disableKeyboard = false; // other reasons
29var arrowscroll     = 50;    // [px]
30
31// Excluded pages
32var exclude = "";
33var disabled = false;
34
35// Other Variables
36var frame = false;
37var direction = { x: 0, y: 0 };
38var initdone  = false;
39var fixedback = true;
40var root = document.documentElement;
41var activeElement;
42
43var key = { left: 37, up: 38, right: 39, down: 40, spacebar: 32, pageup: 33, pagedown: 34, end: 35, home: 36 };
44
45/**
46 * Sets up scrolls array, determines if frames are involved.
47 */
48function init() {
49
50	if (!document.body) return;
51
52	var body = document.body;
53	var html = document.documentElement;
54	var windowHeight = window.innerHeight;
55	var scrollHeight = body.scrollHeight;
56
57	// check compat mode for root element
58	root = (document.compatMode.indexOf('CSS') >= 0) ? html : body;
59	activeElement = body;
60
61	initdone = true;
62
63	// Checks if this script is running in a frame
64	if (top != self) {
65		frame = true;
66	}
67
68	/**
69	 * This fixes a bug where the areas left and right to
70	 * the content does not trigger the onmousewheel event
71	 * on some pages. e.g.: html, body { height: 100% }
72	 */
73	else if (scrollHeight > windowHeight &&
74		(body.offsetHeight <= windowHeight ||
75		html.offsetHeight <= windowHeight)) {
76
77		// DOMChange (throttle): fix height
78		var pending = false;
79		var refresh = function() {
80			if (!pending && html.scrollHeight != document.height) {
81				pending = true; // add a new pending action
82				setTimeout(function(){
83					html.style.height = document.height + 'px';
84					pending = false;
85				}, 500); // act rarely to stay fast
86			}
87		};
88		html.style.height = '';
89		setTimeout(refresh, 10);
90		addEvent("DOMNodeInserted", refresh);
91		addEvent("DOMNodeRemoved",  refresh);
92
93		// clearfix
94		if (root.offsetHeight <= windowHeight) {
95			var underlay = document.createElement("div");
96			underlay.style.clear = "both";
97			body.appendChild(underlay);
98		}
99	}
100
101	// gmail performance fix
102	if (document.URL.indexOf("mail.google.com") > -1) {
103		var s = document.createElement("style");
104		s.innerHTML = ".iu { visibility: hidden }";
105		(document.getElementsByTagName("head")[0] || html).appendChild(s);
106	}
107	// disable fixed background
108	if (!fixedback && !disabled) {
109		body.style.backgroundAttachment = "scroll";
110		html.style.backgroundAttachment = "scroll";
111	}
112}
113
114
115/************************************************
116 * SCROLLING
117 ************************************************/
118
119var que = [];
120var pending = false;
121var lastScroll = +new Date;
122
123/**
124 * Pushes scroll actions to the scrolling queue.
125 */
126function scrollArray(elem, left, top, delay) {
127
128	delay || (delay = 1000);
129	directionCheck(left, top);
130
131	if (acceleration) {
132		var now = +new Date;
133		var elapsed = now - lastScroll;
134		if (elapsed < accelDelta) {
135			var factor = (1 + (30 / elapsed)) / 2;
136			if (factor > 1) {
137				factor = Math.min(factor, accelMax);
138				left *= factor;
139				top  *= factor;
140			}
141		}
142		lastScroll = +new Date;
143	}
144
145	// push a scroll command
146	que.push({
147		x: left,
148		y: top,
149		lastX: (left < 0) ? 0.99 : -0.99,
150		lastY: (top  < 0) ? 0.99 : -0.99,
151		start: +new Date
152	});
153
154	// don't act if there's a pending queue
155	if (pending) {
156		return;
157	}
158
159	var scrollWindow = (elem === document.body);
160
161	var step = function() {
162
163		var now = +new Date;
164		var scrollX = 0;
165		var scrollY = 0;
166
167		for (var i = 0; i < que.length; i++) {
168
169			var item = que[i];
170			var elapsed  = now - item.start;
171			var finished = (elapsed >= animtime);
172
173			// scroll position: [0, 1]
174			var position = (finished) ? 1 : elapsed / animtime;
175
176			// easing [optional]
177			if (pulseAlgorithm) {
178				position = pulse(position);
179			}
180
181			// only need the difference
182			var x = (item.x * position - item.lastX) >> 0;
183			var y = (item.y * position - item.lastY) >> 0;
184
185			// add this to the total scrolling
186			scrollX += x;
187			scrollY += y;
188
189			// update last values
190			item.lastX += x;
191			item.lastY += y;
192
193			// delete and step back if it's over
194			if (finished) {
195				que.splice(i, 1); i--;
196			}
197		}
198
199		// scroll left and top
200		if (scrollWindow) {
201			window.scrollBy(scrollX, scrollY)
202		}
203		else {
204			if (scrollX) elem.scrollLeft += scrollX;
205			if (scrollY) elem.scrollTop  += scrollY;
206		}
207
208		// clean up if there's nothing left to do
209		if (!left && !top) {
210			que = [];
211		}
212
213		if (que.length) {
214			requestFrame(step, elem, (delay / framerate + 1));
215		} else {
216			pending = false;
217		}
218	}
219
220	// start a new queue of actions
221	requestFrame(step, elem, 0);
222	pending = true;
223}
224
225
226/***********************************************
227 * EVENTS
228 ***********************************************/
229
230/**
231 * Mouse wheel handler.
232 * @param {Object} event
233 */
234function wheel(event) {
235
236	if (!initdone) {
237		init();
238	}
239
240	var target = event.target;
241	var overflowing = overflowingAncestor(target);
242
243	// use default if there's no overflowing
244	// element or default action is prevented
245	if (!overflowing || event.defaultPrevented ||
246		isNodeName(activeElement, "embed") ||
247		(isNodeName(target, "embed") && /\.pdf/i.test(target.src))) {
248		return true;
249	}
250
251	var deltaX = event.wheelDeltaX || 0;
252	var deltaY = event.wheelDeltaY || 0;
253
254	// use wheelDelta if deltaX/Y is not available
255	if (!deltaX && !deltaY) {
256		deltaY = event.wheelDelta || 0;
257	}
258
259	// scale by step size
260	// delta is 120 most of the time
261	// synaptics seems to send 1 sometimes
262	if (Math.abs(deltaX) > 1.2) {
263		deltaX *= stepsize / 120;
264	}
265	if (Math.abs(deltaY) > 1.2) {
266		deltaY *= stepsize / 120;
267	}
268
269	scrollArray(overflowing, -deltaX, -deltaY);
270//	event.preventDefault();
271}
272
273/**
274 * Keydown event handler.
275 * @param {Object} event
276 */
277function keydown(event) {
278
279	var target   = event.target;
280	var modifier = event.ctrlKey || event.altKey || event.metaKey ||
281		(event.shiftKey && event.keyCode !== key.spacebar);
282
283	// do nothing if user is editing text
284	// or using a modifier key (except shift)
285	// or in a dropdown
286	if ( /input|textarea|select|embed/i.test(target.nodeName) ||
287		target.isContentEditable ||
288		event.defaultPrevented   ||
289		modifier ) {
290		return true;
291	}
292	// spacebar should trigger button press
293	if (isNodeName(target, "button") &&
294		event.keyCode === key.spacebar) {
295		return true;
296	}
297
298	var shift, x = 0, y = 0;
299	var elem = overflowingAncestor(activeElement);
300	var clientHeight = elem.clientHeight;
301
302	if (elem == document.body) {
303		clientHeight = window.innerHeight;
304	}
305
306	switch (event.keyCode) {
307		case key.up:
308			y = -arrowscroll;
309			break;
310		case key.down:
311			y = arrowscroll;
312			break;
313		case key.spacebar: // (+ shift)
314			shift = event.shiftKey ? 1 : -1;
315			y = -shift * clientHeight * 0.9;
316			break;
317		case key.pageup:
318			y = -clientHeight * 0.9;
319			break;
320		case key.pagedown:
321			y = clientHeight * 0.9;
322			break;
323		case key.home:
324			y = -elem.scrollTop;
325			break;
326		case key.end:
327			var damt = elem.scrollHeight - elem.scrollTop - clientHeight;
328			y = (damt > 0) ? damt+10 : 0;
329			break;
330		case key.left:
331			x = -arrowscroll;
332			break;
333		case key.right:
334			x = arrowscroll;
335			break;
336		default:
337			return true; // a key we don't care about
338	}
339
340	scrollArray(elem, x, y);
341	event.preventDefault();
342}
343
344/**
345 * Mousedown event only for updating activeElement
346 */
347function mousedown(event) {
348	activeElement = event.target;
349}
350
351
352/***********************************************
353 * OVERFLOW
354 ***********************************************/
355
356var cache = {}; // cleared out every once in while
357setInterval(function(){ cache = {}; }, 10 * 1000);
358
359var uniqueID = (function() {
360	var i = 0;
361	return function (el) {
362		return el.uniqueID || (el.uniqueID = i++);
363	};
364})();
365
366function setCache(elems, overflowing) {
367	for (var i = elems.length; i--;)
368		cache[uniqueID(elems[i])] = overflowing;
369	return overflowing;
370}
371
372function overflowingAncestor(el) {
373	var elems = [];
374	var rootScrollHeight = root.scrollHeight;
375	do {
376		var cached = cache[uniqueID(el)];
377		if (cached) {
378			return setCache(elems, cached);
379		}
380		elems.push(el);
381		if (rootScrollHeight === el.scrollHeight) {
382			if (!frame || root.clientHeight + 10 < rootScrollHeight) {
383				return setCache(elems, document.body); // scrolling root in WebKit
384			}
385		} else if (el.clientHeight + 10 < el.scrollHeight) {
386			overflow = getComputedStyle(el, "").getPropertyValue("overflow-y");
387			if (overflow === "scroll" || overflow === "auto") {
388				return setCache(elems, el);
389			}
390		}
391	} while (el = el.parentNode);
392}
393
394
395/***********************************************
396 * HELPERS
397 ***********************************************/
398
399function addEvent(type, fn, bubble) {
400	window.addEventListener(type, fn, (bubble||false));
401}
402
403function removeEvent(type, fn, bubble) {
404	window.removeEventListener(type, fn, (bubble||false));
405}
406
407function isNodeName(el, tag) {
408	return (el.nodeName||"").toLowerCase() === tag.toLowerCase();
409}
410
411function directionCheck(x, y) {
412	x = (x > 0) ? 1 : -1;
413	y = (y > 0) ? 1 : -1;
414	if (direction.x !== x || direction.y !== y) {
415		direction.x = x;
416		direction.y = y;
417		que = [];
418		lastScroll = 0;
419	}
420}
421
422var requestFrame = (function(){
423	return  window.requestAnimationFrame       ||
424	window.webkitRequestAnimationFrame ||
425	function(callback, element, delay){
426		window.setTimeout(callback, delay || (1000/60));
427	};
428})();
429
430/***********************************************
431 * PULSE
432 ***********************************************/
433
434/**
435 * Viscous fluid with a pulse for part and decay for the rest.
436 * - Applies a fixed force over an interval (a damped acceleration), and
437 * - Lets the exponential bleed away the velocity over a longer interval
438 * - Michael Herf, http://stereopsis.com/stopping/
439 */
440function pulse_(x) {
441	var val, start, expx;
442	// test
443	x = x * pulseScale;
444	if (x < 1) { // acceleartion
445		val = x - (1 - Math.exp(-x));
446	} else {     // tail
447		// the previous animation ended here:
448		start = Math.exp(-1);
449		// simple viscous drag
450		x -= 1;
451		expx = 1 - Math.exp(-x);
452		val = start + (expx * (1 - start));
453	}
454	return val * pulseNormalize;
455}
456
457function pulse(x) {
458	if (x >= 1) return 1;
459	if (x <= 0) return 0;
460
461	if (pulseNormalize == 1) {
462		pulseNormalize /= pulse_(1);
463	}
464	return pulse_(x);
465}
466
467var uA = window.navigator.userAgent,
468	safari = /Safari/i.test(uA),
469	chrome = /Chrome/i.test(uA);
470
471
472if( (safari && chrome) || (!safari && chrome) || (!safari && !chrome) ){
473	addEvent("mousedown", mousedown);
474	addEvent("mousewheel", wheel);
475	addEvent("load", init);
476}

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.