PageSourceSearch

https://ukiyogermany.com/js/page-scroll.js

js ukiyogermany.com collected 2026-10-06 02:09:14 UTC 21,650 bytes, 748 lines download raw bytes

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

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.