PageSourceSearch

https://www.blonjon.com/Ext/Resources?a=8dWWA_vGfRxFc91L5QyT6OaFLg…JginG07cvZceOXkXHvFT5E6aAAoHGZBIIu9kmPb2zpr

js blonjon.com collected 2026-09-26 15:28:21 UTC 19,911 bytes, 584 lines download raw bytes

1WS.Namespace.Create('WS.ScrollBar', (function () {
2
3    var SCROLL_DELTA = 100;
4    var SCROLL_DURATION = 200;
5    var CSS_ELEMENT = 'sb-scroll';
6    var CSS_ELEMENT_INIT = 'sb-i';
7    var CSS_ELEMENT_RELATIVE = 'sb-rel';
8    var CSS_SCROLLBAR = 'sb-scrollbar';
9    var CSS_HANDLE = 'sb-handle';
10    var CSS_FULL = 'sb-full';
11    var CSS_ACTIVE = 'sb-active';
12    var IE_VERSION = GetIEVersion();
13    var isIE = IE_VERSION > 0 && IE_VERSION <= 11;
14
15    var __scrollbars = [];
16    var min = Math.min, max = Math.max;
17
18    function ScrollBar(element) {
19        this._element = (typeof element === 'string') ? document.querySelector(element) : element;
20        this._bar = null;
21        this._stopAnimation = null;
22        this._scrollTop = 0;
23        this._scrollAnimationFrame = null;
24        this._initialized = false;
25
26        if (!isIE) {
27            this._onScroll = onScroll.bind(this);
28            this._onMouseOver = isIE ? onMouseOverIE.bind(this) : onMouseOver.bind(this);
29            this._onMouseWheel = onMouseWheel.bind(this);
30            this._onDragStart = onDragStart.bind(this);
31            this._updateBar = updateBar.bind(this);
32        }
33
34    //    if (this._element !== undefined && this._element.tabIndex < 0) this._element.tabIndex = -1;
35
36        if (this._element) {
37
38            __scrollbars.push(this);
39
40            init.call(this);
41            bindEvents.call(this);
42            this.update();
43        }
44    }
45
46    function init() {
47        var element = this._element;
48        this._scrollTop = this._element.scrollTop;
49        this._bar = element.appendChild(renderBar());
50
51        element.classList.add(CSS_ELEMENT);
52        element.classList.add(CSS_ELEMENT_INIT);
53
54        if (isIE) {
55            element.classList.add('sb-scroll-ie');
56        }
57
58        if (window.getComputedStyle(element).position === 'static') {
59            element.classList.add(CSS_ELEMENT_RELATIVE);
60        }
61        this._initialized = true;
62    }
63
64    function bindEvents() {
65        if (isIE) return;
66        this._element.addEventListener('scroll', this._onScroll);
67        this._element.addEventListener('mouseover', this._onMouseOver);
68        this._element.addEventListener('scrollbar:mousewheel', this._onMouseWheel, { passive: false });
69        this._element.addEventListener('keydown', onKeyDown);
70        this._bar.addEventListener('mousedown', this._onDragStart);
71    }
72
73    function unbindEvents() {
74        if (isIE) return;
75        this._element.removeEventListener('scroll', this._onScroll);
76        this._element.removeEventListener('mouseover', this._onMouseOver);
77        this._element.removeEventListener('scrollbar:mousewheel', this._onMouseWheel);
78        this._element.removeEventListener('keydown', onKeyDown);
79        this._bar.removeEventListener('mousedown', this._onDragStart);
80    }
81
82    function setScrollTop(scrollTop) {
83        this._preventNextUpdate = true;
84        this._element.scrollTop = scrollTop;
85        updateBar.call(this);
86    }
87
88    function updateBar() {
89        var element = this._element;
90        var handle = this._bar.children[0];
91        var maxHeight = this._bar.offsetHeight;
92        var maxTop = (maxHeight - handle.offsetHeight) / maxHeight;
93        var top = (element.scrollTop) / (element.scrollHeight - element.offsetHeight) * maxTop;
94
95        this._bar.style.transform = 'translateY(' + element.scrollTop + 'px)';
96        handle.style.top = (top * 100) + '%';
97    }
98
99    function updateHandleHeight() {
100        var element = this._element;
101        var isFull = element.offsetHeight >= element.scrollHeight;
102        this._bar.classList.toggle(CSS_FULL, isFull);
103        this._bar.children[0].style.height = (element.offsetHeight / element.scrollHeight * 100) + '%';
104    }
105
106    function removeEl(element) {
107        return (element.parentElement) ?
108            element.parentElement.removeChild(element) : null;
109    }
110
111    function onKeyDown(event) {
112        var keyCode = ('which' in event) ? event.which : event.keyCode;
113        var scrollbar = ScrollBar.get(event.currentTarget);
114
115        if (!scrollbar || keyCode < 33 || keyCode > 40) return;
116
117        event.preventDefault();
118        event.stopPropagation();
119
120        switch (keyCode) {
121            case 33: return scrollbar.pageUp(true);
122            case 34: return scrollbar.pageDown(true);
123            case 35: return scrollbar.scrollToEnd(true);
124            case 36: return scrollbar.scrollTo(0, true);
125            case 38: return scrollbar.scrollTo(scrollbar._scrollTop - SCROLL_DELTA, true);
126            case 40: return scrollbar.scrollTo(scrollbar._scrollTop + SCROLL_DELTA, true);
127            default: return;
128        }
129    }
130
131    function onScroll(e) {
132        if (!this._initialized) return;
133        if (this._preventNextUpdate) return this._preventNextUpdate = false;
134        this._scrollAnimationFrame = requestAnimationFrame(this._updateBar);
135        this._scrollTop = this._element.scrollTop;
136    }
137
138    function onMouseOver() {
139        this.update();
140    }
141
142    var isOver = false;
143    function onMouseOverIE() {
144        if (isOver) {
145            return;
146        }
147        this.update();
148    }
149
150    function onDragStart(e) {
151        var element = this._element;
152        var mousePos = getMousePos(e);
153        var drag = ScrollBar.dragData;
154
155        if (!ScrollBar.activeBar && element) {
156            var handle = this._bar.children[0];
157
158            if (e.target === this._bar) {
159                var dir = (handle.getBoundingClientRect().top < mousePos[1] ? 1 : -1);
160                this.scrollTo((element.scrollTop + element.offsetHeight * dir), true);
161            } else {
162                onDragEnd();
163                this._element.classList.add(CSS_ACTIVE);
164
165                ScrollBar.activeBar = this;
166
167                drag.maxDeltaTop = 1 - (handle.offsetHeight / this._bar.offsetHeight);
168                drag.containerHeight = element.offsetHeight;
169                drag.height = drag.containerHeight - element.scrollHeight;
170
171                drag.initialY = mousePos[1];
172                drag.initialTop = handle.offsetTop / drag.containerHeight;
173
174                document.addEventListener('mousemove', onDragMove);
175                document.addEventListener('mouseup', onDragEnd);
176            }
177        }
178    }
179
180    function onDragMove(e) {
181        var activeBar;
182        var mousePos = getMousePos(e);
183        var drag = ScrollBar.dragData;
184
185        if (activeBar = ScrollBar.activeBar) {
186            var deltaY = drag.initialY - mousePos[1];
187            var top = (drag.initialTop - (deltaY / drag.containerHeight));
188
189            top *= (activeBar._element.scrollHeight - drag.containerHeight) / drag.maxDeltaTop;
190
191            activeBar.scrollTo(top);
192        } else {
193            onDragEnd();
194        }
195    }
196
197    function onDragEnd() {
198        document.removeEventListener('mousemove', onDragMove);
199        document.removeEventListener('mouseup', onDragEnd);
200
201        if (ScrollBar.activeBar) {
202            ScrollBar.activeBar._element.classList.remove(CSS_ACTIVE);
203            ScrollBar.activeBar = null;
204        }
205    }
206
207    function onMouseWheel(e) {
208        var element = e.currentTarget;
209        var deltaY = e.detail.deltaY;
210
211        if ((deltaY < 0 && element.scrollTop + element.offsetHeight < element.scrollHeight)
212            || (deltaY > 0 && element.scrollTop > 0)) {
213            e.preventDefault();
214            e.stopPropagation();
215        }
216
217        updateHandleHeight.call(this);
218        this.scrollTo(this._scrollTop + (e.detail.deltaFactor * -deltaY), Math.abs(deltaY) === 1);
219    }
220
221    function animateScrollTo(to, duration, complete) {
222        var element = this._element;
223        var start = element.scrollTop;
224        var distance = to - start;
225        var startTime = null;
226        var stopped = false;
227
228        var self = this;
229        var animateScroll = function (timestamp) {
230            if (stopped) return;
231            if (!startTime) {
232                startTime = timestamp;
233            }
234
235            var progress = timestamp - startTime;
236
237            if (progress < duration) {
238                requestAnimationFrame(animateScroll);
239                var delta = distance > 0 ?
240                    max(distance * easeOutQuad(progress / duration), 1) :
241                    min(distance * easeOutQuad(progress / duration), -1);
242                var val = parseInt(start + delta);
243                setScrollTop.call(self, val);
244            } else {
245                self._stopAnimation = null;
246                setScrollTop.call(self, self._scrollTop);
247                complete();
248            }
249        };
250
251        this._stopAnimation = function () { stopped = true };
252
253        requestAnimationFrame(animateScroll);
254    }
255
256    function renderBar() {
257        var scrollbar = document.createElement('div');
258        var handle = document.createElement('div');
259        scrollbar.className = CSS_SCROLLBAR;
260        handle.className = CSS_HANDLE;
261        scrollbar.appendChild(handle);
262        return scrollbar;
263    }
264
265    function getMousePos(event) {
266        return [event.clientX, event.clientY];
267    }
268
269    function easeOutQuad(t) {
270        return t * (2 - t);
271    }
272
273    /**
274     * Private CustomEvent 'scrollbar:mousewheel'
275     */
276    (function () {
277        if (document.attachEvent)
278            document.attachEvent('onwheel', dispatchMouseWheelEvent);
279        else if (document.addEventListener)
280            document.addEventListener('wheel', dispatchMouseWheelEvent, { passive: false, useCapture: false });
281
282        var createCustomEvent = isIE ? function (eventName, options) {
283            var customEvent = document.createEvent('CustomEvent');
284            customEvent.initCustomEvent(eventName, options.bubbles, options.cancelable, {
285                detail: options.detail
286            });
287            return customEvent;
288        } : function (eventName, options) { return new CustomEvent(eventName, options) };
289
290        function dispatchMouseWheelEvent(e) {
291            var closest = null;
292            var deltaY = 0;
293
294            if (!e) e = window.event;
295            if (e.wheelDelta) deltaY = e.wheelDelta / 120;
296            else if (e.detail) deltaY = -e.detail / 3;
297
298            //var scrollableElement = e.composedPath ?
299            //    findScrollableInPath(e.composedPath()) :
300            //    findScrollableParent(e.target);
301
302            var customEvent = createCustomEvent('scrollbar:mousewheel', {
303                bubbles: true,
304                cancelable: true,
305                detail: {
306                    deltaY: deltaY,
307                    deltaFactor: SCROLL_DELTA
308                }
309            });
310
311            //if (scrollableElement && !scrollableElement.classList.contains(CSS_ELEMENT)) {
312            //    return false;
313            //}
314
315            if (!e.target.dispatchEvent(customEvent) && e.preventDefault) {
316                e.preventDefault();
317            }
318        }
319
320        function isScrollable(element) {
321            var overflowY = window.getComputedStyle(element).overflowY;
322            if (element.classList.contains(CSS_ELEMENT) || overflowY === 'auto' || overflowY === 'scroll') {
323                return true;
324            }
325            return false;
326        }
327
328        function findScrollableInPath(eventPath) {
329            if (eventPath) {
330                var len = len = eventPath.indexOf(document.body) || eventPath.length
331                for (var i = 0; i < len; i++) {
332                    if (isScrollable(eventPath[i])) return eventPath[i];
333                }
334            }
335            return null;
336        }
337
338        function findScrollableParent(parent) {
339            if (parent) {
340                if (isScrollable(parent)) return parent;
341                while ((parent = parent.parentElement) && parent !== document.body) {
342                    if (isScrollable(parent)) return parent;
343                }
344            }
345            return null;
346        }
347    })();
348
349    function GetIEVersion() {
350        var sAgent = window.navigator.userAgent;
351        var Idx = sAgent.indexOf("MSIE");
352
353        // If IE, return version number.
354        if (Idx > 0)
355            return parseInt(sAgent.substring(Idx + 5, sAgent.indexOf(".", Idx)));
356
357        // If IE 11 then look for Updated user agent string.
358        else if (!!navigator.userAgent.match(/Trident\/7\./))
359            return 11;
360
361        else
362            return 0; //It is not IE
363    }
364
365    /**
366     * Scrolls to the specified value.
367     * @param {number} scrollTop Element scrollTop property value
368     * @param {boolean|number} duration Animation duration. Set true for default duration.
369     */
370    function scrollTo(scrollTop, duration) {
371        var self = this;
372        var element = this._element;
373
374        if (this._stopAnimation) this._stopAnimation();
375        scrollTop = this._scrollTop = min(max(scrollTop, 0), element.scrollHeight - element.offsetHeight);
376
377        if (!isIE && duration) {
378            if (duration === true) duration = SCROLL_DURATION;
379            animateScrollTo.call(this, scrollTop, duration, function () {
380                self._preventNextUpdate = false;
381            });
382        } else {
383            setScrollTop.call(this, scrollTop);
384        }
385    }
386
387    function scrollToEnd(animated) {
388        return this.scrollTo(this._element.scrollHeight, animated);
389    }
390
391    /**
392     * Scrolls up using the container offset height.
393     * @param {boolean} animated Set true for animated scroll
394     */
395    function pageUp(animated) {
396        this.pageScroll(-1, animated);
397    }
398
399    /**
400     * Scrolls down using the container offsetHeight.
401     * @param {boolean} animated Set true for animated scroll
402     */
403    function pageDown(animated) {
404        this.pageScroll(1, animated);
405    }
406
407    /**
408     * Scrolls down using the container offsetHeight.
409     * @param {number} multiplier Scroll offsetHeight multiplier
410     * @param {boolean} animated Set true for animated scroll
411     */
412    function pageScroll(multiplier, animated) {
413        this.scrollTo(this._scrollTop + this._element.offsetHeight * multiplier, animated);
414    }
415
416    /**
417     * Refreshes the scrollbar style.
418     */
419    function update() {
420        if (!this._initialized) return;
421        if (this._bar.parentElement !== this._element) {
422            this._element.appendChild(this._bar);
423        }
424        updateHandleHeight.call(this);
425        updateBar.call(this);
426    }
427
428    /**
429     * Destroys the scrollbar and clears its event handlers.
430     */
431    function destroy() {
432        if (!this._initialized) return;
433        if (this._stopAnimation) this._stopAnimation();
434        if (this._scrollAnimationFrame) cancelAnimationFrame(this._scrollAnimationFrame);
435        if (this._element && ScrollBar.activeBar === this._element) onDragEnd();
436
437        unbindEvents.call(this);
438
439        this._element.classList.remove(
440            CSS_ELEMENT,
441            CSS_ELEMENT_INIT,
442            CSS_ELEMENT_RELATIVE
443        );
444
445        if (removeEl(this._bar)) {
446            var scrollbarIndex = __scrollbars.indexOf(this);
447
448            this._element = null;
449            this._bar = null;
450
451            if (scrollbarIndex >= 0) {
452                __scrollbars.splice(scrollbarIndex, 1);
453            }
454
455            this._initialized = false;
456            return true;
457        }
458
459        return false;
460    }
461
462    ScrollBar.activeBar = null;
463
464    ScrollBar.dragData = {
465        containerHeight: 0,
466        maxTop: 0,
467        initialTop: 0,
468        initialY: 0,
469        deltaY: 0
470    };
471
472    ScrollBar.__scrollbars = __scrollbars;
473
474    /**
475     * Returns the attached ScrollBar instance using the specified element.
476     * @param {HtmlElement} element The scrollable container
477     */
478    ScrollBar.get = function (element) {
479        if (typeof element === 'string') {
480            element = document.querySelector(element);
481        }
482        for (var i = 0, len = __scrollbars.length; i < len; i++) {
483            if (__scrollbars[i]._element === element) {
484                return __scrollbars[i];
485            }
486        }
487        return null;
488    };
489
490    /**
491     * Initializes a new ScrollBar instance into a container and makes it scrollable.
492     * @param {HtmlElement} element The scrollable container
493     * @param {boolean} forced Set true to force a new instance and destroy the old one.
494     */
495    ScrollBar.init = function (element, forced) {
496        var scrollbar = ScrollBar.get(element);
497
498        if (forced && scrollbar) scrollbar.destroy();
499
500        if (!scrollbar) {
501            scrollbar = new ScrollBar(element);
502        }
503
504        return scrollbar;
505    };
506
507    /**
508     * Initializes all selected elements matching the selector below:
509     * ```css
510     *  .sb-scroll,[sb-scroll],[data-sb-scroll]
511     * ```
512     * @param {boolean} forced Set true to force all new instances.
513     */
514    ScrollBar.initAll = function (forced) {
515        var containers = document.querySelectorAll('.sb-scroll,[sb-scroll],[data-sb-scroll]');
516        var scrollbars = [];
517        for (var i = 0, len = containers.length; i < len; i++) {
518            scrollbars.push(ScrollBar.init(containers[i], forced));
519        }
520        return scrollbars;
521    };
522
523    /**
524     * Destroys the registered ScrollBar instance of the element.
525     * @param {HtmlElement} element The scrollable container.
526     */
527    ScrollBar.destroy = function (element) {
528        var scrollbar = ScrollBar.get(element);
529        if (scrollbar) scrollbar.destroy();
530        return !!scrollbar;
531    };
532
533    /**
534     * Destroys all registered ScrollBar instances.
535     */
536    ScrollBar.destroyAll = function () {
537        var scrollbars = [].concat(__scrollbars);
538        var destroyedCount = 0;
539        for (var i = 0, len = scrollbars.length; i < len; i++) {
540            if (scrollbars[i].destroy()) destroyedCount++;
541        }
542        return destroyedCount;
543    };
544
545    /**
546     * Polyfill for requestAnimationFrame
547     */
548    (function () {
549        var lastTime = 0;
550        var vendors = ['ms', 'moz', 'webkit', 'o'];
551        for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
552            window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
553            window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame']
554                || window[vendors[x] + 'CancelRequestAnimationFrame'];
555        }
556
557        if (!window.requestAnimationFrame)
558            window.requestAnimationFrame = function (callback, element) {
559                var currTime = new Date().getTime();
560                var timeToCall = Math.max(0, 16 - (currTime - lastTime));
561                var id = window.setTimeout(function () { callback(currTime + timeToCall); },
562                    timeToCall);
563                lastTime = currTime + timeToCall;
564                return id;
565            };
566
567        if (!window.cancelAnimationFrame)
568            window.cancelAnimationFrame = function (id) {
569                clearTimeout(id);
570            };
571    }());
572
573    window.addEventListener('load', function () { ScrollBar.initAll(false) }, false);
574
575    ScrollBar.prototype.scrollTo = scrollTo;
576    ScrollBar.prototype.scrollToEnd = scrollToEnd;
577    ScrollBar.prototype.pageUp = pageUp;
578    ScrollBar.prototype.pageDown = pageDown;
579    ScrollBar.prototype.pageScroll = pageScroll;
580    ScrollBar.prototype.update = update;
581    ScrollBar.prototype.destroy = destroy;
582
583    return ScrollBar;
584})());

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.