PluginProbe
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN / 1.4.2
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN v1.4.2
1.4.2 1.4.1 1.4.0 1.3.7 1.3.6 1.3.5 1.3.4 1.3.3 1.3.2 1.3.1 1.3.0 1.2.4 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 All 36 releases
← All changes | includes/js/delay-bootstrap.js +46 -0 1.4.0 → 1.4.2 View file →
@@ -99,8 +99,12 @@
99 99 started = true;
100 100 TRIGGERS.forEach(function (name) {
101 101 window.removeEventListener(name, start, { passive: true, capture: true });
102 102 });
103 + // Marks the start, before any delayed script is put back. The Elementor
104 + // entrance-animation reveal listens for it to settle the widgets the
105 + // visitor has already seen.
106 + document.dispatchEvent(new Event('xspeed:replaying'));
103 107 var nav = window.performance && performance.getEntriesByType && performance.getEntriesByType('navigation')[0];
104 108 if (nav && nav.domContentLoadedEventStart > 0) dclFired = true;
105 109
106 110 // pageLoaded: the replay starts after load, the usual case ("late").
@@ -216,8 +220,48 @@
216 220 var currentOnload = pageOnload;
217 221 var currentRsc = pageRsc;
218 222 var jq = window.jQuery;
219 223 var ended;
224 +
225 + // jQuery ready. When jQuery ran before the replay and is already ready,
226 + // jQuery(fn) and $(document).ready(fn) run fn on the next timer, which
227 + // can come before a later delayed script has arrived. On a real page
228 + // ready waits for DOMContentLoaded, so every deferred script has run
229 + // first. Elementor's frontend calls init from ready, and Elementor Pro, a
230 + // later script, listens for the event init sends: run early, Pro missed
231 + // it and its sticky header and motion effects never started. So while
232 + // the replay runs, ready only queues, and the queue goes to jQuery's own
233 + // ready with the synthetic DOMContentLoaded. jQuery(fn) goes through
234 + // jQuery.fn.ready, so one wrapper covers both forms.
235 + var heldReady = [];
236 + var pageReady;
237 + var ourReady;
238 + try {
239 + if (jq && jq.fn && jq.isReady && jq.fn.ready) {
240 + pageReady = jq.fn.ready;
241 + ourReady = jq.fn.ready = function (fn) {
242 + // Only while the queue is open: once released, a call that still
243 + // reaches us (through a wrapper put on top) goes straight through.
244 + if (ourReady) {
245 + heldReady.push(fn);
246 + return this;
247 + }
248 + return pageReady.apply(this, arguments);
249 + };
250 + }
251 + } catch (e) {}
252 + // Puts jQuery's ready back (unless something wrapped it after us) and
253 + // hands it the queue, in order. jQuery runs each on a timer, as usual,
254 + // and catches what they throw, so this call itself does not throw.
255 + function releaseReady() {
256 + if (!ourReady) return;
257 + if (jq.fn.ready === ourReady) jq.fn.ready = pageReady;
258 + ourReady = 0;
259 + heldReady.forEach(function (fn) {
260 + pageReady.call(jq(document), fn);
261 + });
262 + heldReady = [];
263 + }
220 264 if (pageLoaded && pageOnload) currentOnload = window.onload = function () {};
221 265 if (pageLoaded && pageRsc) currentRsc = document.onreadystatechange = function () {};
222 266
223 267 // The replayed scripts read a fake document.readyState: 'loading' while
@@ -373,8 +417,9 @@
373 417 fakeDepth++;
374 418 fireReadyStateChange();
375 419 }
376 420 firePrivate(document, 'DOMContentLoaded', 1);
421 + releaseReady();
377 422 if (faking) fakeDepth--;
378 423 if (pageLoaded && !faking) fireReadyStateChange();
379 424 pending = 1;
380 425 var $ = window.jQuery;
@@ -402,8 +447,9 @@
402 447 // since been put on top; `live` makes ours inert either way.
403 448 function finish() {
404 449 if (ended) return;
405 450 ended = 1;
451 + releaseReady();
406 452 if (observer) observer.disconnect();
407 453 if (faking) {
408 454 if (ownReadyState) Object.defineProperty(document, 'readyState', ownReadyState);
409 455 else delete document.readyState;