PageSourceSearch

https://www.dioshpt.org/wp-content/plugins/divi-essential/includes…/preloader/assets/preloader.js?ver=5.9.0

js dioshpt.org collected 2026-09-24 21:58:19 UTC 11,151 bytes, 371 lines download raw bytes

1/**
2 * Divi Essential — Preloader extension (front-end runtime).
3 *
4 * Hides the overlay once BOTH the content-ready gate has passed AND the minimum
5 * display time has elapsed (whichever is later), then fades out. The gate is
6 * `viewport` (above-the-fold media only — the default) or `full_load`
7 * (window.load); see `hideOn` below.
8 * Loaded in <head>, so the overlay element may not exist yet at parse time —
9 * DOM access is deferred to DOMContentLoaded.
10 */
11(function () {
12	"use strict";
13
14	// Config ships as an inert <script type="application/json"> tag printed
15	// before this script, because JS optimizers (NitroPack, WP Rocket delay-JS,
16	// LiteSpeed…) rewrite executable inline scripts into their delayed loaders
17	// but leave non-executable types alone. The global is the legacy fallback
18	// for cached pages generated by older plugin versions.
19	var cfg = (function () {
20		var node = document.getElementById("dnxte-preloader-config");
21		if (node) {
22			try {
23				var parsed = JSON.parse(node.textContent);
24				if (parsed && typeof parsed === "object") {
25					return parsed;
26				}
27			} catch (e) {}
28		}
29		return window.dnxtePreloaderData || {};
30	})();
31	var minTime = parseInt(cfg.minDisplayTime, 10) || 0;
32	var fadeDur = parseInt(cfg.fadeOutDuration, 10) || 0;
33	var onceSession = cfg.showFrequency === "once_session";
34	var SESSION_KEY = "dnxtePreloaderShown";
35	var SAFETY_MS = 10000; // Force-hide if `load` never fires.
36	var ASSET_MS = 3000; // Per-asset ceiling for the viewport gate (see whenViewportReady).
37
38	var root = document.documentElement;
39
40	// "Once per session": if already shown, suppress before paint and bail.
41	if (onceSession && sessionStorage.getItem(SESSION_KEY)) {
42		var skip = document.createElement("style");
43		skip.textContent = "#dnxte-preloader{display:none!important}";
44		(document.head || root).appendChild(skip);
45		return;
46	}
47
48	// Lock scroll while the overlay is visible.
49	root.classList.add("dnxte-preloader-active");
50
51	var loaded = false;
52	var minElapsed = false;
53	var done = false;
54
55	// Set by initStepText so the content-ready gate can advance any step bound to
56	// the `load` milestone. In viewport mode we hide before window.load fires, so
57	// without this the final step would never be shown.
58	var onLoadedForSteps = null;
59
60	var start = Date.now();
61
62	function getEl() {
63		return document.getElementById("dnxte-preloader");
64	}
65
66	function unlock() {
67		root.classList.remove("dnxte-preloader-active");
68	}
69
70	function hide() {
71		if (done) {
72			return;
73		}
74		done = true;
75
76		var el = getEl();
77		if (!el) {
78			unlock();
79			return;
80		}
81
82		el.classList.add("dnxte-preloader--hide");
83
84		var remove = function () {
85			if (el && el.parentNode) {
86				el.parentNode.removeChild(el);
87			}
88			unlock();
89			if (onceSession) {
90				try {
91					sessionStorage.setItem(SESSION_KEY, "1");
92				} catch (e) {}
93			}
94		};
95
96		// Remove after the fade transition (with a small buffer).
97		window.setTimeout(remove, fadeDur + 50);
98	}
99
100	function maybeHide() {
101		if (loaded && minElapsed) {
102			hide();
103		}
104	}
105
106	// Gate 1: minimum display time.
107	window.setTimeout(function () {
108		minElapsed = true;
109		maybeHide();
110	}, minTime);
111
112	// Gate 2: content ready.
113	//
114	// `full_load` waits for window.load — i.e. every image and iframe on the page,
115	// including everything below the fold. `viewport` waits only for the media that
116	// is actually visible in the first screenful (plus fonts), which is all the user
117	// can see behind the overlay. window.load is still wired up in both modes as a
118	// fallback, so viewport mode can only ever hide EARLIER, never later.
119	function markLoaded() {
120		loaded = true;
121		if (typeof onLoadedForSteps === "function") {
122			onLoadedForSteps();
123		}
124		maybeHide();
125	}
126
127	if (document.readyState === "complete") {
128		markLoaded();
129	} else {
130		window.addEventListener("load", markLoaded);
131
132		if (cfg.hideOn === "viewport") {
133			whenViewportReady(markLoaded);
134		}
135	}
136
137	/**
138	 * Resolve once the above-the-fold media has settled.
139	 *
140	 * "Above the fold" is measured at DOMContentLoaded against the initial
141	 * viewport height. Each wait resolves on error too, and every wait is capped at
142	 * ASSET_MS, so a broken or never-settling asset cannot stall the overlay — and
143	 * the window.load + SAFETY_MS fallbacks still apply.
144	 */
145	function whenViewportReady(cb) {
146		function run() {
147			var fold = window.innerHeight || 0;
148			var waits = [];
149
150			function inFold(node) {
151				var r = node.getBoundingClientRect();
152				// Skip zero-size (display:none / not yet laid out) nodes.
153				if (!r.width && !r.height) {
154					return false;
155				}
156				return r.top < fold && r.bottom > -1;
157			}
158
159			// Resolve once `node` has its content, per element type. Getting the
160			// "already done" test right matters more than the listener: if an asset
161			// finished before we got here and we only listen, the event has already
162			// been missed and the wait hangs forever.
163			function settle(node) {
164				return new Promise(function (res) {
165					var tag = node.tagName;
166
167					if ("IMG" === tag) {
168						// `complete` covers cached images.
169						if (node.complete) {
170							res();
171							return;
172						}
173					} else if ("VIDEO" === tag) {
174						// <video> never fires `load` — only loadedmetadata/loadeddata.
175						// preload="none" fetches nothing until play(), so there is
176						// nothing to await. HAVE_METADATA (1) is our bar: preload
177						// defaults to "metadata" in Chrome, which stops at 1 and never
178						// fires `loadeddata`, so waiting for a decoded frame would hang
179						// on nearly every video. At metadata the box is laid out and the
180						// poster paints, which is all the gate needs.
181						if ("none" === node.preload || node.readyState >= 1) {
182							res();
183							return;
184						}
185						node.addEventListener("loadedmetadata", res, { once: true });
186					} else if ("IFRAME" === tag) {
187						// Same-origin (about:blank, srcdoc, src-less) is readable and
188						// is usually already complete by DOMContentLoaded. Cross-origin
189						// throws — fall through to the load listener + the ASSET_MS cap.
190						try {
191							var doc = node.contentDocument;
192							if (doc && "complete" === doc.readyState) {
193								res();
194								return;
195							}
196						} catch (e) {}
197					}
198
199					// `error` resolves too, so a 404 asset can never hold the gate open.
200					node.addEventListener("load", res, { once: true });
201					node.addEventListener("error", res, { once: true });
202				});
203			}
204
205			// Nothing may hold the gate open indefinitely. Racing every wait against
206			// a fixed ceiling makes that true for asset types we haven't special-cased
207			// yet, instead of silently falling back to window.load.
208			function capped(p) {
209				return Promise.race([
210					p,
211					new Promise(function (res) {
212						window.setTimeout(res, ASSET_MS);
213					}),
214				]);
215			}
216
217			var nodes = document.querySelectorAll("img, video, iframe");
218			for (var i = 0; i < nodes.length; i++) {
219				if (inFold(nodes[i])) {
220					waits.push(settle(nodes[i]));
221				}
222			}
223
224			// CSS background-images are the common case for Divi heroes and are NOT
225			// covered by the tag query above; without this the overlay would lift
226			// before the hero paints, which looks worse than waiting.
227			var all = document.querySelectorAll("*");
228			var seen = {};
229			for (var j = 0; j < all.length; j++) {
230				var node = all[j];
231				if (!inFold(node)) {
232					continue;
233				}
234				var bg = getComputedStyle(node).backgroundImage;
235				if (!bg || bg === "none") {
236					continue;
237				}
238				var m = bg.match(/url\((['"]?)(.*?)\1\)/);
239				if (!m || !m[2] || seen[m[2]]) {
240					continue;
241				}
242				seen[m[2]] = true;
243				waits.push(settle(Object.assign(new Image(), { src: m[2] })));
244			}
245
246			if (document.fonts && document.fonts.ready && typeof document.fonts.ready.then === "function") {
247				waits.push(document.fonts.ready);
248			}
249
250			Promise.all(waits.map(capped)).then(cb, cb);
251		}
252
253		if (document.readyState === "loading") {
254			document.addEventListener("DOMContentLoaded", run, { once: true });
255		} else {
256			run();
257		}
258	}
259
260	// Safety net: never block the page indefinitely.
261	window.setTimeout(function () {
262		loaded = true;
263		minElapsed = true;
264		maybeHide();
265	}, Math.max(SAFETY_MS, minTime + 1000));
266
267	// --- Step-by-step loading text (milestone-based) ---
268	// Advances the text node through enabled steps as real load milestones fire,
269	// holding each step for at least `dwell` ms so it stays readable. The first
270	// step is already rendered server-side; this only handles steps 2..N.
271	var stepCfg = cfg.stepText || {};
272	if (stepCfg.enabled && Array.isArray(stepCfg.steps) && stepCfg.steps.length > 1) {
273		initStepText(stepCfg);
274	}
275
276	function initStepText(sc) {
277		var steps = sc.steps;
278		var dwell = parseInt(sc.dwell, 10) || 0;
279		var SWAP_MS = 150; // must match the CSS fade duration.
280
281		// Which milestones have fired. `init` is true from the start.
282		var fired = { init: true, dom: false, fonts: false, load: false };
283
284		var current = 0; // index of the currently shown step (0 = server-seeded).
285		var lastShownAt = Date.now();
286		var stepEl = null;
287
288		function el() {
289			if (!stepEl) {
290				stepEl = document.querySelector(".dnxte-preloader__steps");
291			}
292			return stepEl;
293		}
294
295		function show(idx) {
296			current = idx;
297			lastShownAt = Date.now();
298			var node = el();
299			if (!node) {
300				return;
301			}
302			node.classList.add("is-swapping");
303			window.setTimeout(function () {
304				node.textContent = steps[idx].text;
305				node.classList.remove("is-swapping");
306			}, SWAP_MS);
307		}
308
309		// Advance as far as the fired milestones and the dwell gate allow.
310		function tick() {
311			if (done) {
312				return; // overlay already hidden.
313			}
314			var next = current + 1;
315			if (next >= steps.length) {
316				return;
317			}
318			if (!fired[steps[next].milestone]) {
319				return; // its milestone hasn't fired yet.
320			}
321			var waited = Date.now() - lastShownAt;
322			if (waited < dwell) {
323				window.setTimeout(tick, dwell - waited);
324				return;
325			}
326			show(next);
327			window.setTimeout(tick, dwell); // the following milestone may already be ready.
328		}
329
330		function markFired(name) {
331			fired[name] = true;
332			tick();
333		}
334
335		// DOMContentLoaded milestone.
336		if (document.readyState === "interactive" || document.readyState === "complete") {
337			fired.dom = true;
338		} else {
339			document.addEventListener("DOMContentLoaded", function () {
340				markFired("dom");
341			});
342		}
343
344		// Fonts milestone — guard for browsers without the Font Loading API.
345		if (document.fonts && document.fonts.ready && typeof document.fonts.ready.then === "function") {
346			document.fonts.ready.then(function () {
347				markFired("fonts");
348			});
349		} else {
350			fired.fonts = true; // treat as reached so it never stalls.
351		}
352
353		// window.load milestone.
354		if (document.readyState === "complete") {
355			fired.load = true;
356		} else {
357			window.addEventListener("load", function () {
358				markFired("load");
359			});
360		}
361
362		// In viewport mode the overlay hides before window.load, so let the
363		// content-ready gate satisfy this milestone too (whichever comes first).
364		onLoadedForSteps = function () {
365			markFired("load");
366		};
367
368		// Kick off (covers milestones that were already satisfied synchronously).
369		tick();
370	}
371})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.