mirror of
https://github.com/storybookjs/storybook.git
synced 2025-03-19 05:02:40 +08:00
HTML: copy support for components that include script tags from sb/aem
This commit is contained in:
parent
8915f3c2cf
commit
fe81d26703
97
app/html/src/client/preview/helpers/simulate-pageload.ts
Normal file
97
app/html/src/client/preview/helpers/simulate-pageload.ts
Normal file
@ -0,0 +1,97 @@
|
||||
import { document } from 'global';
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/scripting.html
|
||||
const runScriptTypes = [
|
||||
'application/javascript',
|
||||
'application/ecmascript',
|
||||
'application/x-ecmascript',
|
||||
'application/x-javascript',
|
||||
'text/ecmascript',
|
||||
'text/javascript',
|
||||
'text/javascript1.0',
|
||||
'text/javascript1.1',
|
||||
'text/javascript1.2',
|
||||
'text/javascript1.3',
|
||||
'text/javascript1.4',
|
||||
'text/javascript1.5',
|
||||
'text/jscript',
|
||||
'text/livescript',
|
||||
'text/x-ecmascript',
|
||||
'text/x-javascript',
|
||||
];
|
||||
|
||||
const SCRIPT = 'script';
|
||||
const SCRIPTS_ROOT_ID = 'scripts-root';
|
||||
|
||||
// trigger DOMContentLoaded
|
||||
export function simulateDOMContentLoaded() {
|
||||
const DOMContentLoadedEvent = document.createEvent('Event');
|
||||
DOMContentLoadedEvent.initEvent('DOMContentLoaded', true, true);
|
||||
document.dispatchEvent(DOMContentLoadedEvent);
|
||||
}
|
||||
|
||||
function insertScript($script: any, callback: any, $scriptRoot: any) {
|
||||
const scriptEl = document.createElement('script');
|
||||
scriptEl.type = 'text/javascript';
|
||||
if ($script.src) {
|
||||
scriptEl.onload = callback;
|
||||
scriptEl.onerror = callback;
|
||||
scriptEl.src = $script.src;
|
||||
} else {
|
||||
scriptEl.textContent = $script.innerText;
|
||||
}
|
||||
|
||||
// re-insert the script tag so it executes.
|
||||
if ($scriptRoot) $scriptRoot.appendChild(scriptEl);
|
||||
else document.head.appendChild(scriptEl);
|
||||
|
||||
// clean-up
|
||||
$script.parentNode.removeChild($script);
|
||||
|
||||
// run the callback immediately for inline scripts
|
||||
if (!$script.src) callback();
|
||||
}
|
||||
|
||||
// runs an array of async functions in sequential order
|
||||
/* eslint-disable no-param-reassign, no-plusplus */
|
||||
function insertScriptsSequentially(scriptsToExecute: any[], callback: any, index: number = 0) {
|
||||
scriptsToExecute[index](() => {
|
||||
index++;
|
||||
if (index === scriptsToExecute.length) {
|
||||
callback();
|
||||
} else {
|
||||
insertScriptsSequentially(scriptsToExecute, callback, index);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function simulatePageLoad($container: any) {
|
||||
let $scriptsRoot = document.getElementById(SCRIPTS_ROOT_ID);
|
||||
if (!$scriptsRoot) {
|
||||
$scriptsRoot = document.createElement('div');
|
||||
$scriptsRoot.id = SCRIPTS_ROOT_ID;
|
||||
document.body.appendChild($scriptsRoot);
|
||||
} else {
|
||||
$scriptsRoot.innerHTML = '';
|
||||
}
|
||||
const $scripts = Array.from($container.querySelectorAll(SCRIPT));
|
||||
|
||||
if ($scripts.length) {
|
||||
const scriptsToExecute: any[] = [];
|
||||
$scripts.forEach(($script: any) => {
|
||||
const typeAttr = $script.getAttribute('type');
|
||||
|
||||
// only run script tags without the type attribute
|
||||
// or with a javascript mime attribute value
|
||||
if (!typeAttr || !runScriptTypes.includes(typeAttr)) {
|
||||
scriptsToExecute.push((callback: any) => insertScript($script, callback, $scriptsRoot));
|
||||
}
|
||||
});
|
||||
|
||||
// insert the script tags sequentially
|
||||
// to preserve execution order
|
||||
insertScriptsSequentially(scriptsToExecute, simulateDOMContentLoaded, undefined);
|
||||
} else {
|
||||
simulateDOMContentLoaded();
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import { document, Node } from 'global';
|
||||
import dedent from 'ts-dedent';
|
||||
import { RenderContext } from './types';
|
||||
import { simulatePageLoad, simulateDOMContentLoaded } from './helpers/simulate-pageload';
|
||||
|
||||
const rootElement = document.getElementById('root');
|
||||
|
||||
@ -17,6 +18,7 @@ export default function renderMain({
|
||||
showMain();
|
||||
if (typeof element === 'string') {
|
||||
rootElement.innerHTML = element;
|
||||
simulatePageLoad(rootElement);
|
||||
} else if (element instanceof Node) {
|
||||
// Don't re-mount the element if it didn't change and neither did the story
|
||||
if (rootElement.firstChild === element && forceRender === true) {
|
||||
@ -25,6 +27,7 @@ export default function renderMain({
|
||||
|
||||
rootElement.innerHTML = '';
|
||||
rootElement.appendChild(element);
|
||||
simulateDOMContentLoaded();
|
||||
} else {
|
||||
showError({
|
||||
title: `Expecting an HTML snippet or DOM node from the story: "${name}" of "${kind}".`,
|
||||
|
@ -24,3 +24,6 @@ export const Effect = () => {
|
||||
|
||||
return '<button id="button">I should be yellow</button>';
|
||||
};
|
||||
|
||||
export const Script = () =>
|
||||
'<div>JS alert</div><script>alert("hello")</script>';
|
||||
|
Loading…
x
Reference in New Issue
Block a user