Enhance theme loading by tracking animation frames, MutationObservers, and intervals; wrap JS in IIFE for scope isolation
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 37s
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 37s
This commit is contained in:
@@ -370,9 +370,69 @@
|
||||
console.log('[Test Site] Theme cleared.');
|
||||
}
|
||||
|
||||
// Track active animation frames and observers for cleanup
|
||||
let activeAnimationFrames = [];
|
||||
let activeBlobUrls = [];
|
||||
|
||||
// Patch requestAnimationFrame and MutationObserver to track them
|
||||
const origRAF = window.requestAnimationFrame;
|
||||
const origCAF = window.cancelAnimationFrame;
|
||||
let trackingEnabled = false;
|
||||
|
||||
window.requestAnimationFrame = function(cb) {
|
||||
const id = origRAF.call(window, cb);
|
||||
if (trackingEnabled) activeAnimationFrames.push(id);
|
||||
return id;
|
||||
};
|
||||
|
||||
window.cancelAnimationFrame = function(id) {
|
||||
origCAF.call(window, id);
|
||||
activeAnimationFrames = activeAnimationFrames.filter(f => f !== id);
|
||||
};
|
||||
|
||||
// Track MutationObservers created by themes
|
||||
let activeObservers = [];
|
||||
const OrigMO = window.MutationObserver;
|
||||
window.MutationObserver = class extends OrigMO {
|
||||
constructor(cb) {
|
||||
super(cb);
|
||||
if (trackingEnabled) activeObservers.push(this);
|
||||
}
|
||||
};
|
||||
|
||||
// Track intervals created by themes
|
||||
let activeIntervals = [];
|
||||
const origSetInterval = window.setInterval;
|
||||
const origClearInterval = window.clearInterval;
|
||||
window.setInterval = function(...args) {
|
||||
const id = origSetInterval.apply(window, args);
|
||||
if (trackingEnabled) activeIntervals.push(id);
|
||||
return id;
|
||||
};
|
||||
window.clearInterval = function(id) {
|
||||
origClearInterval.call(window, id);
|
||||
activeIntervals = activeIntervals.filter(i => i !== id);
|
||||
};
|
||||
|
||||
function loadTheme() {
|
||||
clearTheme();
|
||||
|
||||
// Cancel all tracked animation frames
|
||||
activeAnimationFrames.forEach(id => origCAF.call(window, id));
|
||||
activeAnimationFrames = [];
|
||||
|
||||
// Disconnect all tracked MutationObservers
|
||||
activeObservers.forEach(obs => obs.disconnect());
|
||||
activeObservers = [];
|
||||
|
||||
// Clear all tracked intervals
|
||||
activeIntervals.forEach(id => origClearInterval.call(window, id));
|
||||
activeIntervals = [];
|
||||
|
||||
// Revoke old blob URLs
|
||||
activeBlobUrls.forEach(url => URL.revokeObjectURL(url));
|
||||
activeBlobUrls = [];
|
||||
|
||||
const value = select.value;
|
||||
if (!value || value === '') return;
|
||||
|
||||
@@ -403,16 +463,31 @@
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
|
||||
// Inject JS (after a short delay to let CSS load)
|
||||
// Inject JS wrapped in IIFE to avoid const redeclaration errors
|
||||
if (jsFile) {
|
||||
setTimeout(() => {
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
const response = await fetch(jsFile);
|
||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||
const code = await response.text();
|
||||
|
||||
// Wrap in IIFE so each theme has its own scope
|
||||
const wrappedCode = `(function() {\n${code}\n})();`;
|
||||
const blob = new Blob([wrappedCode], { type: 'application/javascript' });
|
||||
const blobUrl = URL.createObjectURL(blob);
|
||||
activeBlobUrls.push(blobUrl);
|
||||
|
||||
trackingEnabled = true;
|
||||
const script = document.createElement('script');
|
||||
script.src = jsFile;
|
||||
script.src = blobUrl;
|
||||
script.setAttribute('data-seasonal', 'true');
|
||||
script.onerror = () => console.error(`[Test Site] Failed to load JS: ${jsFile}`);
|
||||
script.onerror = () => console.error(`[Test Site] Failed to execute JS: ${jsFile}`);
|
||||
document.body.appendChild(script);
|
||||
console.log(`[Test Site] Loaded theme: ${value} (${jsFile})`);
|
||||
}, 100);
|
||||
console.log(`[Test Site] Loaded theme: ${value} (${jsFile}) [IIFE-wrapped]`);
|
||||
} catch (err) {
|
||||
console.error(`[Test Site] Failed to load JS: ${jsFile}`, err);
|
||||
}
|
||||
}, 150);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user