Greasy Fork is available in English.

waitForKeyElementsInDocument

NOT TESTED YET waitForKeyElements version with possibility to work on other DOM Documents. Uses ES6, no JQuery or other frameworks required.

Ce script ne doit pas être installé directement. C'est une librairie destinée à être incluse dans d'autres scripts avec la méta-directive // @require https://greasyfork.org/scripts/369404-waitforkeyelementsindocument/code/waitForKeyElementsInDocument.js?version=606324

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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// ==UserScript==
// @name            waitForKeyElementsInDocument
// @namespace       https://greasyfork.org/users/190012-zerk
// @version         0.1.4
// @description     NOT TESTED YET waitForKeyElements version with possibility to work on other DOM Documents. Uses ES6, no JQuery or other frameworks required.
// @author          zerk
// @icon            https://www.greasespot.net/favicon.ico
// @include         http*://*/*
// @grant           unsafeWindow
// ==/UserScript==

// code based on https://greasyfork.org/scripts/38889-waitforkeyelements-2018-userscript-library/code

/**
 * Delay
 * @constant
 */
const delay = 100;

/**
 * Unique identifier
 * @constant
 */
const uuid = `wfke_${(GM_info.script.name).replace(/[^a-zA-Z0-9_.]/gi, '').toLowerCase()}_${Math.random().toString(36).substring(2, 15)}`;

/**
 * Request id of requestAnimationFrame
 * @global
 */
let requestId = unsafeWindow.requestId || null;
unsafeWindow.requestId = requestId;

/**
 * Selector dictionary
 * @global
 */
const selectorMap = unsafeWindow.selectorMap || {};
unsafeWindow.selectorMap = selectorMap;

/**
 * didStartLookup
 * @global
 */
let didStartLookup = false;
unsafeWindow.didStartLookup = didStartLookup;

/**
 * Has started lookup
 * @returns {Boolean} - Yes/No
 */
let hasStartedLookup = () => unsafeWindow.didStartLookup;

/**
 * Stop lookup
 */
let stopLookup = () => {
    window.cancelAnimationFrame(unsafeWindow.requestId);
    unsafeWindow.requestId = null;
    delete unsafeWindow.requestId;
};

/**
 * Register selector
 * @param {String} selector - CSS selector of elements to search / monitor ('.comment')
 * @param {function} callback - Callback executed on element detection (called with element as argument)
 * @param {Boolean=} findOnce - Stop lookup after the last currently available element has been found
 * @param {String=} targetSelector - CSS selector of nested element to limit search to ('#footer')
 */
let registerSelector = (selector, callback, findOnce, checkerFunction, targetSelector) => {
    unsafeWindow.selectorMap[selector] = {
        callback,
        findOnce,
        checkerFunction,
        targetSelector
    };

    // DEBUG
    console.debug('[waitForKeyElements]', `[${selector}]`, 'selector added');
};

/**
 * Register selector
 * @param {String} selector - CSS selector
 * @returns {Boolean} - Yes/No
 */
let hasRegisteredSelector = (selector) => unsafeWindow.selectorMap[selector];

/**
 * Unregister selector
 * @param {String} selector - CSS selector
 */
let unregisterSelector = (selector) => {
    unsafeWindow.selectorMap[selector] = null;
    delete unsafeWindow.selectorMap[selector];

    // DEBUG
    // console.log('[waitForKeyElements]', `[${selector}]`, 'selector complete');

    // Last selector? Cancel requestAnimationFrame
    if (Object.keys(unsafeWindow.selectorMap).length === 0) {
        stopLookup();

        // DEBUG
        console.debug('[waitForKeyElements]', 'all selectors complete');
    }
};

let waitForKeyElementsInDocument = (selector, callback, findOnce = false, checkerFunction = null, targetSelector = '', doc = window.document) => {
    // Init
    let elementList;
    let didFindNewElement = false;
    
    // Find elements
    if (Boolean(targetSelector)) {
        elementList = doc.querySelector(targetSelector).querySelectorAll(selector) || [];
    } else {
        elementList = doc.querySelectorAll(selector) || [];
    }

    // Is element new?
    if (elementList.length > 0) {
        elementList.forEach((element) => {
            if(checkerFunction && checkerFunction(element)) {             
                // Add <data> attribute to newly discovered nodes
                if (element.dataset[uuid] !== 'found') {
                    element.dataset[uuid] = 'found';
                    didFindNewElement = true;

                    // Callback
                    callback(element);

                    // DEBUG
                    console.debug('[waitForKeyElements]', `[${selector}"]`, 'element found');
                }
            }
        });
    }

    // Register selector
    if (!hasRegisteredSelector(selector)) {
        registerSelector(selector, callback, findOnce, checkerFunction, targetSelector);
    }

    // Running once? Check if element found
    if (hasRegisteredSelector(selector) && findOnce && didFindNewElement) {
        unregisterSelector(selector);
    } else {
        if (!hasStartedLookup()) {
            unsafeWindow.didStartLookup = true;
            let lastTime = Date.now();
            let lookupLoop = () => {
                if (Date.now() >= (lastTime + delay)) {
                    lastTime = Date.now();

                    // Loop through registered selectors
                    Object.keys(unsafeWindow.selectorMap).forEach((selector) => {
                        waitForKeyElementsInDocument(selector, unsafeWindow.selectorMap[selector].callback, unsafeWindow.selectorMap[selector].findOnce, unsafeWindow.selectorMap[selector].checkerFunction, unsafeWindow.selectorMap[selector].targetSelector);
                    });

                    // Verbose
                    // console.debug('[waitForKeyElements]', lastTime, `[${selector}]`, 'lookup cycle complete');
                }

                unsafeWindow.requestId = window.requestAnimationFrame(lookupLoop);
            };
            lookupLoop();
        }
    }
};