PageSourceSearch

https://i2hard.ru/local/templates/i2hard2020/js/dist/fakescroll.js?16397554208188

js i2hard.ru collected 2026-10-02 05:19:53 UTC 8,188 bytes, 204 lines download raw bytes

1/**
2 * By Yair Even Or (C)
3 * https://github.com/yairEO/fakescroll
4 */
5;(function(){
6    raf = window.requestAnimationFrame || function(cb) { return window.setTimeout(cb, 1000 / 60) };
7
8    function FakeScroll(targetElm, settings){
9        if( !targetElm ) return;
10
11        this.settings = Object.assign({}, this.defaults, settings || {})
12        this.callback = settings.callback ? settings.callback : null
13
14        this.state = {}
15        this.listeners = {}
16
17        this.DOM = this.build(targetElm)
18        this.events.binding.call(this, this.DOM)
19
20        // run "moveBar" once
21        setTimeout(this.events.callbacks.onScrollResize.bind(this))
22    }
23
24    FakeScroll.prototype = {
25        defaults : {
26            classname : "",
27            track     : false // "smooth" will enable smooth scroll
28        },
29
30        /**
31         * Build the DOM needed
32         */
33        build( targetElm ){
34            var DOM = {};
35                scopeHTML = `<div class="fakeScroll__wrap">
36                                <div class="fakeScroll__content"></div>
37                             </div>
38                             <div class='fakeScroll__track ${this.settings.classname}'>
39                                <div class="fakeScroll__bar"></div>
40                             </div>`,
41                fragment = document.createDocumentFragment();
42
43            // move all the children of the target element into a fragment
44            while( targetElm.childNodes.length ){
45                fragment.appendChild(targetElm.childNodes[0]);
46            }
47
48            targetElm.insertAdjacentHTML('afterbegin', scopeHTML);
49
50            DOM.scope = targetElm;
51            DOM.scrollWrap = targetElm.firstElementChild;
52            DOM.scrollContent = DOM.scrollWrap.firstElementChild;
53            DOM.scrollContent.appendChild(fragment);
54
55            DOM.track = DOM.scrollWrap.nextElementSibling;
56            DOM.bar = DOM.track.firstElementChild;
57
58            DOM.scope.classList.add("fakeScroll");
59
60            return DOM;
61        },
62
63        destroy(){
64            this.events.off.call(this, window, 'resize', 'onScrollResize');
65        },
66
67        events : {
68            on(elm, eName, cbName){
69                // to be able tp unbind the events, callback refferece must be saved somewhere
70                eName.split(' ').forEach(e => {
71                    if( !(cbName in this.events.callbacks) ) console.warn(cbName, " doesn't exist in Callbacks: ", this.events.callbacks);
72
73                    this.listeners[e] = this.events.callbacks[cbName].bind(this);
74                    elm.addEventListener(e, this.listeners[e])
75                });
76
77                return this.events;
78            },
79
80            off(elm, eName, cbName){
81                eName.split(' ').forEach(e => elm.removeEventListener(e, this.listeners[e]))
82                return this.events;
83            },
84
85            binding(DOM){
86                this.events.on.call(this, DOM.scrollContent, 'scroll', 'onScrollResize')
87                           .on.call(this, DOM.scope, 'mouseenter', 'onScrollResize')
88                           .on.call(this, DOM.bar, 'mousedown', 'onBarMouseDown')
89                           .on.call(this, window, 'resize', 'onScrollResize')
90
91                if( this.settings.track )
92                    this.events.on.call(this, DOM.track, 'click', 'onTrackClick')
93            },
94
95            /**
96             * events only binded when Bar element gets a "mousedown" event
97             * @param  {[type]} onOff [description]
98             * @return {[type]}       [description]
99             */
100            drag(onOff){
101                this.events[onOff].call(this, document, 'mousemove', 'onDrag')
102                           [onOff].call(this, document, 'mouseup', 'onStopDrag')
103            },
104
105            callbacks : {
106                onScrollResize(){
107                    this.moveBar.call(this);
108                    this.DOM.scope.classList.toggle('fakeScroll--hasBar', this.state.scrollRatio < 1)
109
110                    // debounce - get track bounds
111                    clearTimeout(this.listeners.timeout__resize);
112                    this.listeners.timeout__resize = setTimeout(this.getTrackBounds.bind(this), 200)
113                },
114
115                onDrag(e){
116                    var delta = e.pageY - this.state.lastPageY;
117
118                    raf(() => {
119                        var sTop = document.documentElement.scrollTop,
120                            isDragWithinTrackBounds = e.pageY >= (this.state.trackBounds.top + sTop) && e.pageY <= (this.state.trackBounds.bottom + sTop);
121
122                        if( isDragWithinTrackBounds )
123                            this.DOM.scrollContent.scrollTop = this.state.drag + delta / this.state.scrollRatio;
124                        // update variables when mouse position is outside the Track bounds
125                        else{
126                            this.state.drag = this.DOM.scrollContent.scrollTop;
127                            this.state.lastPageY = e.pageY;
128                        }
129                    });
130                },
131
132                onStopDrag(e){
133                    [this.DOM.bar, document.body].map(el => el.classList.remove('fakeScroll--grabbed'))
134                    this.events.drag.call(this, 'off');
135                    setTimeout(()=>{ this.state.drag = false })
136                },
137
138                onBarMouseDown(e){
139                    this.state.drag = this.DOM.scrollContent.scrollTop;
140                    this.state.lastPageY = e.pageY;
141
142                    [this.DOM.bar, document.body].map(el => el.classList.add('fakeScroll--grabbed'))
143                    this.events.drag.call(this, 'on');
144                },
145
146                onTrackClick(e){
147                    if( this.state.drag ) return;
148
149                    var perc         = (e.clientY - this.state.trackBounds.top) / (this.state.trackBounds.height - this.state.trackBounds.topPad - this.state.trackBounds.bottomPad),
150                        scrollHeight = this.DOM.scrollContent.scrollHeight,
151                        ownHeight    = this.DOM.scrollWrap.clientHeight,
152                        newScrollTop = perc * (scrollHeight - ownHeight);
153
154                    if( this.settings.track == 'smooth' ){
155                        this.DOM.scrollContent.style.scrollBehavior = 'smooth';
156                        setTimeout(()=>{ this.DOM.scrollContent.style.scrollBehavior = 'unset' }, 500)
157                    }
158
159                    this.DOM.scrollContent.scrollTop = newScrollTop;
160                }
161            }
162        },
163
164        getTrackBounds(){
165            var bounds = this.DOM.track.getBoundingClientRect(),
166                styles = window.getComputedStyle(this.DOM.track, null);
167
168            bounds.topPad = parseInt(styles.paddingTop, 10);
169            bounds.bottomPad = parseInt(styles.paddingBottom, 10);
170
171            this.state.trackBounds = bounds;
172            return bounds;
173        },
174
175        moveBar(){
176            // if( !this.DOM.scrollContent ) return false;
177
178            var _scrollContent = this.DOM.scrollContent,
179                scrollHeight = _scrollContent.scrollHeight,
180                ownHeight   = this.DOM.scrollWrap.clientHeight;
181
182            this.state.scrollRatio = this.DOM.track.clientHeight / scrollHeight;
183
184            // update fake scrollbar location on the Y axis using requestAnimationFrame
185            raf(()=> {
186                var height = (ownHeight / scrollHeight) * 100,
187                    top = (_scrollContent.scrollTop / scrollHeight ) * 100;
188
189                this.DOM.bar.style.cssText = `height  : ${height}%;
190                                              top     : ${top}%;
191                                              display : ${scrollHeight <= ownHeight ? 'none' : ''}`;
192            });
193        }
194    }
195
196    /**
197     * Extend the DOM with "fakeScroll" method. The chances of the same name already be taken are slim to none,
198     * But you should now; it's your code you're putting this into.
199     */
200    Element.prototype.fakeScroll = function( settings ){
201        this._fakeScroll = this._fakeScroll || new FakeScroll(this, settings || {});
202        return this._fakeScroll;
203    }
204})();

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.