aboutsummaryrefslogtreecommitdiff
path: root/resources/assets/javascripts/bootstrap/installer.js
blob: 4a83b7e039ef5abdba593e90dc07eddeb07a0146 (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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
function domReady(fn) {
    if (document.readyState === 'complete' || document.readyState === 'interactive') {
        setTimeout(fn, 1);
    } else {
        document.addEventListener('DOMContentLoaded', fn);
    }
}

domReady(() => {
    if (!('fetch' in window) || !('Promise' in window)) {
        const hidden_input = document.createElement('input');
        hidden_input.setAttribute('type', 'hidden');
        hidden_input.setAttribute('name', 'basic');
        hidden_input.setAttribute('value', 1);
        document.querySelector('form').append(hidden_input);

        return;
    }

    var requests = [];
    document.querySelectorAll('dl.requests > dt[data-request-url]').forEach((element) => {
        requests.push({
            element: element,
            url: element.dataset.requestUrl,
            event_source: element.dataset.eventSource !== undefined
        });
    });

    const submit_button = document.querySelector('form button[type="submit"].button');
    submit_button.disabled = true;

    function next() {
        if (requests.length === 0) {
            submit_button.disabled = false;
            return;
        }
        const current = requests.shift();
        var promise;

        current.element.classList.add('requesting');

        if (current.event_source && 'EventSource' in window) {
            const notifier = document.createElement('div');
            notifier.setAttribute('data-percent', 0);

            promise = new Promise((resolve, reject) => {
                current.element.classList.add('event-sourced');

                const progress = current.element.nextElementSibling.nextElementSibling.nextElementSibling;
                var total = 0;

                progress.insertAdjacentElement('afterend', notifier);
                notifier.setAttribute(
                    'style',
                    `left: ${progress.offsetLeft}px; top: ${progress.offsetTop}px`
                );

                const evtSource = new EventSource(current.url + '?evts=1', {
                    withCredentials: true
                });
                evtSource.addEventListener('total', (event) => {
                    total = parseInt(event.data, 10);
                    progress.setAttribute('max', total);
                });
                evtSource.addEventListener('file', (event) => {
                    notifier.setAttribute('data-file', event.data);
                });
                evtSource.addEventListener('current', (event) => {
                    let current = parseInt(event.data, 10);
                    progress.setAttribute('value', current);
                    notifier.setAttribute('data-percent', (100 * current / total).toFixed(2));
                });
                evtSource.addEventListener('error', (event) => {
                    evtSource.close();
                    reject(event.data || 'Fehler beim Installieren');
                });
                evtSource.addEventListener('close', () => {
                    evtSource.close();
                    resolve();
                });
            });

            promise.finally(() => {
                if (notifier.parentNode) {
                    notifier.parentNode.removeChild(notifier);
                }
                current.element.classList.remove('event-sourced');
            });
        } else {
            promise = fetch(current.url, {
                cache: 'no-cache',
                credentials: 'same-origin'
            }).then(response => {
                if (!response.ok) {
                    return response.json().then(message => {
                        return Promise.reject(message);
                    });
                }
            });
        }

        promise.then(() => {
            current.element.classList.add('succeeded');
            next();
        }).catch(error => {
            current.element.classList.add('failed');

            if (error !== null && error === Object(error)) {
                current.element.nextElementSibling.nextElementSibling.querySelectorAll('.response').forEach((element) => {
                    let key = element.dataset.key;
                    element.value = error[key];
                });
            } else {
                current.element.nextElementSibling.nextElementSibling.querySelector('.response').innerText = error;
            }
        }).finally(() => {
            current.element.classList.remove('requesting');
        });
    }

    next();
});