eiffel-tower-llama / app /src /components /HtmlFragment.astro
thibaud frere
update
fee9c1e
raw
history blame
2.1 kB
---
interface Props { src: string }
const { src } = Astro.props as Props;
// Charge tous les fragments .html sous src/fragments/** en tant que string (dev & build)
const fragments = import.meta.glob('../fragments/**/*.html', { query: '?raw', import: 'default', eager: true }) as Record<string, string>;
function resolveFragment(requested: string): string | null {
// Autorise "banner.html" ou "fragments/banner.html"
const needle = requested.replace(/^\/*/, '');
for (const [key, html] of Object.entries(fragments)) {
if (key.endsWith('/' + needle) || key.endsWith('/' + needle.replace(/^fragments\//, ''))) {
return html;
}
}
return null;
}
const html = resolveFragment(src);
const mountId = `frag-${Math.random().toString(36).slice(2)}`;
---
{ html ? (
<div id={mountId} set:html={html} />
) : (
<div><!-- Fragment introuvable: {src} --></div>
) }
<script>
// Ré-exécuter les <script> présents dans le fragment injecté (innerHTML n'exécute pas les scripts)
const scriptEl = document.currentScript;
const mount = scriptEl ? scriptEl.previousElementSibling : null;
const execute = () => {
if (!mount) return;
const scripts = mount.querySelectorAll('script');
scripts.forEach(old => {
// ignorer les types non exécutables (ex: application/json)
if (old.type && old.type !== 'text/javascript' && old.type !== 'module' && old.type !== '') return;
if (old.dataset.executed === 'true') return;
old.dataset.executed = 'true';
if (old.src) {
const s = document.createElement('script');
Array.from(old.attributes).forEach(({ name, value }) => s.setAttribute(name, value));
document.body.appendChild(s);
} else {
try {
// exécuter inline
(0, eval)(old.text || '');
} catch (e) {
console.error('HtmlFragment inline script error:', e);
}
}
});
};
// Si Plotly n'est pas encore chargé, attendre l'événement load
if (window.Plotly) execute();
else window.addEventListener('load', execute, { once: true });
</script>