aboutsummaryrefslogtreecommitdiff
path: root/resources/assets/javascripts/lib/scroll.js
blob: a4d24d5d55fdfa7d0ca707b1ea325542bb885396 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/**
 * Provides means to hook into the scroll event. Registered callbacks are
 * called with the current scroll top and scroll left position so both
 * vertical and horizontal scroll events can be handled.
 *
 * Updates/calls to the callback are synchronized to screen refresh by using
 * the animation frame method (which will fallback to a timer based solution).
 */
var handlers = {};
var animId = false;

var lastTop  = null;
var lastLeft = null;

function scrollHandler() {
    var scrollTop = $(document).scrollTop();
    var scrollLeft = $(document).scrollLeft();

    if (scrollTop !== lastTop || scrollLeft !== lastLeft) {
        $.each(handlers, function(index, handler) {
            handler(scrollTop, scrollLeft);
        });

        lastTop  = scrollTop;
        lastLeft = scrollLeft;
    }

    animId = false;

    engageScrollTrigger();
}

function refresh() {
    var hasHandlers = !$.isEmptyObject(handlers);
    if (!hasHandlers && animId !== false) {
        window.cancelAnimationFrame(animId);
        animId = false;
    } else if (hasHandlers && animId === false) {
        animId = window.requestAnimationFrame(scrollHandler);
    }
}

function engageScrollTrigger() {
    $(window).off('scroll.studip-handler');
    $(window).one('scroll.studip-handler', refresh);
}

const Scroll = {
    addHandler(index, handler) {
        handlers[index] = handler;
        engageScrollTrigger();
    },
    removeHandler(index) {
        delete handlers[index];
        engageScrollTrigger();
    }
};

export default Scroll;