<commit_before>import debounce from '../utils/debounce.service';
const mod = angular.module('pa.scrollSpy.scrollContainer', [debounce.name]);

mod.directive('paScrollContainer', ($window, $timeout, paDebounce) => {
    return {
        restrict: 'A',
        controller ($scope, $element) {
            this.spies = [];
            this.registerSpy = (spy) => {
                this.spies.push(spy);
            };

            this.getScrollContainer = () => {
                return $element[0];
            };
        },
        link (scope, elem, attrs, selfCtrl) {
            let vpHeight,
                $aWindow = angular.element($window),
                scroller = elem[0].tagName === 'BODY' ? $aWindow : elem;

            function onScroll() {
                $window.requestAnimationFrame(onAnimationFrame);
            }

            function onResize() {
                vpHeight = Math.max($window.document.documentElement.clientHeight, window.innerHeight || 0);
                selfCtrl.spies.forEach((spy)=> {
                    spy.updateClientRect();
                });
                $window.requestAnimationFrame(onAnimationFrame);
            }

            function onAnimationFrame() {
                const viewportRect = getViewportRect();
                selfCtrl.spies.forEach((spy)=> {
                    spy.update(viewportRect);
                });

            }

            function getViewportRect() {
                const currentScroll = elem[0].scrollTop;
                return {
                    top: currentScroll,
                    height: vpHeight
                };
            }

            $aWindow.on('resize', paDebounce(onResize, 300));
            scroller.on('scroll', onScroll);
            onResize();
        }
    };
});

export default mod;
<commit_msg>Make sure the animation frame is called for a defined delta also if no scroll events are triggered #30<commit_after>import debounce from '../utils/debounce.service';
const mod = angular.module('pa.scrollSpy.scrollContainer', [debounce.name]);

mod.directive('paScrollContainer', ($window, $timeout, paDebounce) => {
    return {
        restrict: 'A',
        controller ($scope, $element) {
            this.spies = [];
            this.registerSpy = (spy) => {
                this.spies.push(spy);
            };

            this.getScrollContainer = () => {
                return $element[0];
            };
        },
        link (scope, elem, attrs, selfCtrl) {
            const afTimeout = 200;
            let vpHeight,
                $aWindow = angular.element($window),
                scroller = elem[0].tagName === 'BODY' ? $aWindow : elem,
                animationFrame,
                lastScrollTimestamp = 0,
                prevTimestamp = 0;

            function onScroll() {
                lastScrollTimestamp = $window.performance.now();
                if (!animationFrame) {
                    animationFrame = $window.requestAnimationFrame(onAnimationFrame);
                }
            }

            function onResize() {
                vpHeight = Math.max($window.document.documentElement.clientHeight, window.innerHeight || 0);
                selfCtrl.spies.forEach((spy)=> {
                    spy.updateClientRect();
                });
                onScroll();
            }

            function onAnimationFrame() {
                const viewportRect = getViewportRect(),
                        timestamp = $window.performance.now();

                selfCtrl.spies.forEach((spy)=> {
                    spy.update(viewportRect);
                });

                var delta = timestamp - prevTimestamp;

                prevTimestamp = timestamp;
                if (timestamp - timestamp < afTimeout) {
                    queueAf();
                } else {
                    cancelAf();
                }

            }

            function getViewportRect() {
                const currentScroll = elem[0].scrollTop;
                return {
                    top: currentScroll,
                    height: vpHeight
                };
            }

            function queueAf() {
                animationFrame = $window.requestAnimationFrame(onAnimationFrame);
            }

            function cancelAf() {
                $window.cancelAnimationFrame(animationFrame);
                animationFrame = null;
            }

            $aWindow.on('resize', paDebounce(onResize, 300));
            scroller.on('scroll', onScroll);
            onResize();
        }
    };
});

export default mod;

{'fraction_non_alphanumeric': 0.11118378024852844, 'fraction_numerical': 0.004578155657292348, 'mean_word_length': 1.3983272347098799, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6639223', 'n_tokens_mistral': 1184, 'n_tokens_neox': 1095, 'n_words': 209}