From 5610f330b90625825dbb05dad5fa832a75968465 Mon Sep 17 00:00:00 2001 From: Andrew Holland Date: Tue, 7 Nov 2023 15:00:01 -0500 Subject: [PATCH 1/4] trying to fix readystate race condition --- src/htmx.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/htmx.js b/src/htmx.js index 79a4702e8..6065460ce 100644 --- a/src/htmx.js +++ b/src/htmx.js @@ -3742,7 +3742,7 @@ return (function () { if (isReady || getDocument().readyState === 'complete') { fn(); } else { - getDocument().addEventListener('DOMContentLoaded', fn); + getDocument().addEventListener('readystatechange', () => ready(fn), {once:true}); } } From d65939daa19b79455defb054a5b7c9c9ae68611b Mon Sep 17 00:00:00 2001 From: Andrew Holland Date: Tue, 7 Nov 2023 15:12:22 -0500 Subject: [PATCH 2/4] es6 to es5 --- src/htmx.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/htmx.js b/src/htmx.js index 6065460ce..7a9dc5e3b 100644 --- a/src/htmx.js +++ b/src/htmx.js @@ -3742,7 +3742,7 @@ return (function () { if (isReady || getDocument().readyState === 'complete') { fn(); } else { - getDocument().addEventListener('readystatechange', () => ready(fn), {once:true}); + getDocument().addEventListener('readystatechange', function() {ready(fn)}, {once:true}); } } From 92c0c3881e38a7b382c2b7f583e72e8cd33e736a Mon Sep 17 00:00:00 2001 From: Andrew Holland Date: Wed, 8 Nov 2023 17:33:17 -0500 Subject: [PATCH 3/4] serialized intitialization routines --- src/htmx.js | 50 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/src/htmx.js b/src/htmx.js index 7a9dc5e3b..b6ef6fc7b 100644 --- a/src/htmx.js +++ b/src/htmx.js @@ -3724,28 +3724,52 @@ return (function () { //==================================================================== // Initialization //==================================================================== - var isReady = false - getDocument().addEventListener('DOMContentLoaded', function() { - isReady = true - }) + /** + * We want to initialize the page elements after DOMContentLoaded + * fires, but there isn't always a good way to tell whether + * it has already fired or not. + */ + var isReady = false; + if ( getDocument().readyState === "complete" ) { + // DOMContentLoaded definitely already fired + isReady = true; + } else { + // DOMContentLoaded *maybe* already fired, so we'll + // watch for a DOM or a readystate event + getDocument().addEventListener('DOMContentLoaded', function() { + isReady = true; + readyComplete(); + }); + getDocument().addEventListener('readystatechange', function() { + if ( getDocument().readyState !== 'complete' ) return; + + isReady = true; + readyComplete(); + }); + } /** - * Execute a function now if DOMContentLoaded has fired, otherwise listen for it. - * - * This function uses isReady because there is no realiable way to ask the browswer whether - * the DOMContentLoaded event has already been fired; there's a gap between DOMContentLoaded - * firing and readystate=complete. + * Execute a function now if DOMContentLoaded + * has fired, otherwise wait for it to happen. */ + var pendingCalls = []; function ready(fn) { - // Checking readyState here is a failsafe in case the htmx script tag entered the DOM by - // some means other than the initial page load. - if (isReady || getDocument().readyState === 'complete') { + if ( isReady ) { fn(); } else { - getDocument().addEventListener('readystatechange', function() {ready(fn)}, {once:true}); + pendingCalls.push( fn ); } } + /** + * Execute the function calls which were queued up + * by ready() before the page had loaded. + */ + function readyComplete() { + forEach( pendingCalls, function(fn) { fn() }); + pendingCalls = []; + } + function insertIndicatorStyles() { if (htmx.config.includeIndicatorStyles !== false) { getDocument().head.insertAdjacentHTML("beforeend", From f5c12c8688901514c969585c11f6ddd423ff81e5 Mon Sep 17 00:00:00 2001 From: Andrew Holland Date: Mon, 20 Nov 2023 10:08:47 -0500 Subject: [PATCH 4/4] encapsulating ready function call --- src/htmx.js | 61 ++++++++++++++++++++--------------------------------- 1 file changed, 23 insertions(+), 38 deletions(-) diff --git a/src/htmx.js b/src/htmx.js index b6ef6fc7b..6a805fe3f 100644 --- a/src/htmx.js +++ b/src/htmx.js @@ -3727,47 +3727,32 @@ return (function () { /** * We want to initialize the page elements after DOMContentLoaded * fires, but there isn't always a good way to tell whether - * it has already fired or not. + * it has already fired when we get here or not. */ - var isReady = false; - if ( getDocument().readyState === "complete" ) { - // DOMContentLoaded definitely already fired - isReady = true; - } else { - // DOMContentLoaded *maybe* already fired, so we'll - // watch for a DOM or a readystate event - getDocument().addEventListener('DOMContentLoaded', function() { - isReady = true; - readyComplete(); - }); - getDocument().addEventListener('readystatechange', function() { - if ( getDocument().readyState !== 'complete' ) return; - - isReady = true; - readyComplete(); - }); - } + function ready(functionToCall) { + // call the function exactly once no matter how many times this is called + var callReadyFunction = function() { + if (!functionToCall) return; + functionToCall(); + functionToCall = null; + }; - /** - * Execute a function now if DOMContentLoaded - * has fired, otherwise wait for it to happen. - */ - var pendingCalls = []; - function ready(fn) { - if ( isReady ) { - fn(); - } else { - pendingCalls.push( fn ); + if (getDocument().readyState === "complete") { + // DOMContentLoaded definitely fired, we can initialize the page + callReadyFunction(); + } + else { + /* DOMContentLoaded *maybe* already fired, wait for + * the next DOMContentLoaded or readystatechange event + */ + getDocument().addEventListener("DOMContentLoaded", function() { + callReadyFunction(); + }); + getDocument().addEventListener("readystatechange", function() { + if (getDocument().readyState !== "complete") return; + callReadyFunction(); + }); } - } - - /** - * Execute the function calls which were queued up - * by ready() before the page had loaded. - */ - function readyComplete() { - forEach( pendingCalls, function(fn) { fn() }); - pendingCalls = []; } function insertIndicatorStyles() {