aboutsummaryrefslogtreecommitdiff
path: root/app/src/web/ts/click_a.ts
blob: 1fd63683f1b0d3ac57495e4cfea67a2f7c65639c (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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
(function () {
    let prevented = false;

    /**
     * Go up at most [depth] times, to retrieve a parent matching the provided predicate
     * If one is found, it is returned immediately.
     * Otherwise, null is returned.
     */
    function _parentEl(el: HTMLElement, depth: number, predicate: (el: HTMLElement) => boolean): HTMLElement | null {
        for (let i = 0; i < depth + 1; i++) {
            if (predicate(el)) {
                return el
            }
            const parent = el.parentElement;
            if (!parent) {
                return null
            }
            el = parent
        }
        return null
    }

    /**
     * Attempts to find a url entry at most [depth] away
     * A url is found if the element has tag 'A', and the url isn't blank
     */
    function _parentUrl(el: HTMLElement, depth: number): string | null {
        const element = _parentEl(el, depth, (el) => el.tagName === 'A');
        if (!element) {
            return null;
        }
        const url = element.getAttribute('href');
        if (!url || url === '#') {
            return null;
        }
        return url
    }

    /**
     * Given event and target, return true if handled and false otherwise.
     */
    type EventHandler = (e: Event, target: HTMLElement) => Boolean

    const _frostGeneral: EventHandler = (e, target) => {
        // Notifications are two layers under
        const url = _parentUrl(target, 2);
        return Frost.loadUrl(url);
    };

    const _frostLaunchpadClick: EventHandler = (e, target) => {
        if (!_parentEl(target, 6, (el) => el.id === 'launchpad')) {
            return false
        }
        console.log('Clicked launchpad');
        const url = _parentUrl(target, 5);
        return Frost.loadUrl(url);
    };

    const handlers: EventHandler[] = [_frostLaunchpadClick, _frostGeneral];

    const _frostAClick = (e: Event) => {
        if (prevented) {
            console.log("Click intercept prevented");
            return
        }
        /*
         * Commonality; check for valid target
         */
        const target = e.target || e.currentTarget || e.srcElement;
        if (!(target instanceof HTMLElement)) {
            console.log("No element found");
            return
        }
        for (const h of handlers) {
            if (h(e, target)) {
                e.stopPropagation();
                e.preventDefault();
                return
            }
        }
    };

    /*
     * On top of the click event, we must stop it for long presses
     * Since that will conflict with the context menu
     * Note that we only override it on conditions where the context menu
     * Will occur
     */
    const _frostPreventClick = () => {
        console.log("Click _frostPrevented");
        prevented = true;
    };

    const _frostAllowClick = () => {
        prevented = false;
        clearTimeout(clickTimeout)
    };

    document.addEventListener('click', _frostAClick, true);
    let clickTimeout: number | undefined = undefined;
    document.addEventListener('touchstart', () => {
        clickTimeout = setTimeout(_frostPreventClick, 400);
    }, true);
    document.addEventListener('touchend', _frostAllowClick, true);
}).call(undefined);