PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.7.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.7.0
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / js / delay-js.js

delay-js.js in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 4.7.0, at js/delay-js.js

183 lines 5.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function() {
2 var is_handling = false;
3
4 /**
5 * Handles the loading of a single script element. If the script element has a `data-type`
6 * attribute, it updates the script type accordingly. If the script element has a `data-src`
7 * attribute, it updates the source and attempts to load it.
8 *
9 * @param {HTMLElement} script_element
10 * @returns {Promise}
11 */
12 function handle_script_element(script_element) {
13 // If 'data-type' is defined, update the script element's type
14 update_script_element_type(script_element);
15
16 // If 'data-src' is defined, update the script's source and load it
17 return update_script_element_src(script_element);
18 }
19
20 /**
21 * Recursively loads script elements one by one. Once a script is successfully loaded,
22 * the next script in the array is loaded. If all scripts are loaded, the function resolves,
23 * otherwise, it rejects on the first error encountered.
24 *
25 * @param {number} index - The current index of the script element being processed.
26 * @param {NodeListOf<HTMLElementTagNameMap[string]>} script_elements - An array of script elements to be loaded.
27 * @param {function} resolve - A function to call when all scripts have been successfully loaded.
28 * @param {function} reject - A function to call if an error occurs during loading of any script.
29 */
30 function load_next_script(index, script_elements, resolve, reject) {
31
32 if (index < script_elements.length) {
33 handle_script_element(script_elements[index])
34 .then(function() {
35 load_next_script(index + 1, script_elements, resolve, reject);
36 })
37 .catch(function() {
38 load_next_script(index + 1, script_elements, resolve, reject);
39 });
40 } else {
41 all_scripts_loaded();
42 resolve();
43 }
44
45 }
46
47 /**
48 * For the given list of script elements with type="text/plain", replace the current script element
49 * with the appropriate type or replace the src attribute with the data-src value for externally loaded scripts.
50 *
51 * @param {NodeListOf<HTMLElementTagNameMap[string]>} script_elements
52 * @returns {Promise}
53 */
54 function load_scripts_sequentially(script_elements) {
55 // Wrap everything in a Promise to handle asynchronous loading
56 return new Promise(function(resolve, reject) {
57 load_next_script(0, script_elements, resolve, reject);
58 });
59 }
60
61 /**
62 * Replaces the current script element with a new one, setting the type attribute to the value of data-type.
63 *
64 * @param {HTMLElement} script_element
65 */
66 function update_script_element_type(script_element) {
67 const data_type = script_element.getAttribute('data-type');
68 const no_delay_js = script_element.hasAttribute('data-no-delay-js');
69
70 if (!data_type || no_delay_js) return;
71
72 script_element.type = data_type;
73 script_element.removeAttribute('data-type');
74
75 const new_script = script_element.cloneNode(true);
76
77 // Replace the original script tag with the new one
78 // We use replaceChild to exclude script running
79 script_element.parentNode.replaceChild(new_script, script_element);
80 }
81
82 /**
83 * Updates the `src` attribute of a script element and removes its `data-src` attribute.
84 * Returns a promise that resolves when the script is successfully loaded or rejects if the script fails to load.
85 *
86 * @param {HTMLElement} script_element
87 * @returns {Promise}
88 */
89 function update_script_element_src(script_element) {
90 return new Promise(function(resolve, reject) {
91 const no_delay_js = script_element.hasAttribute('data-no-delay-js');
92 const data_src = script_element.getAttribute('data-src');
93
94 // If there's no 'data-src', resolve the promise immediately
95 if (!data_src || no_delay_js) {
96 return resolve();
97 }
98
99 script_element.src = data_src;
100 script_element.removeAttribute('data-src');
101
102 // Event listener for script load completion
103 script_element.onload = resolve;
104 script_element.onerror = reject;
105 });
106 }
107
108
109 /**
110 * Called when all delayed scripts have loaded. Triggers DOMContentLoaded and load events to run their handlers in delayed scripts.
111 */
112 function all_scripts_loaded() {
113 window.wpo_delayed_scripts_loaded = true;
114
115 var event = new Event('DOMContentLoaded');
116 document.dispatchEvent(event);
117 // Create a new load event
118 event = new Event('load');
119 // Dispatch the load event on the window
120 window.dispatchEvent(event);
121 }
122
123 /**
124 * List of events to trigger delayed script loading.
125 *
126 * @return {string[]}
127 */
128 function get_event_list() {
129 return [
130 'scroll',
131 'mousemove',
132 'mouseover',
133 'resize',
134 'touchstart',
135 'touchmove',
136 ];
137 }
138
139 /**
140 * Adds event listeners to trigger delayed script loading on user interaction.
141 */
142 function attach_event_listeners() {
143 get_event_list().forEach(function (event) {
144 window.addEventListener(event, handle_delay_js);
145 });
146 }
147
148 /**
149 * Removes event listeners that were added to trigger delayed script loading.
150 */
151 function remove_event_listeners() {
152 get_event_list().forEach(function (event) {
153 window.removeEventListener(event, handle_delay_js);
154 });
155 }
156
157 /**
158 * Get all script elements and load them if their loading was delayed.
159 *
160 * @return {void}
161 */
162 function handle_delay_js() {
163
164 if (is_handling) return;
165
166 is_handling = true;
167
168 // Remove all event listeners after the first call
169 remove_event_listeners();
170
171 const script_elements = document.querySelectorAll('script');
172
173 load_scripts_sequentially(script_elements);
174 }
175
176 // Attach events on any manipulation with the page
177 document.addEventListener('DOMContentLoaded', function () {
178 if (!window.wpo_delayed_scripts_loaded) {
179 attach_event_listeners();
180 }
181 });
182 })();
183