diff --git a/core/package-lock.json b/core/package-lock.json
index 1ba6ccb3e68..aaf34cbee24 100644
--- a/core/package-lock.json
+++ b/core/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@pyscript/core",
- "version": "0.7.18",
+ "version": "0.7.24",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@pyscript/core",
- "version": "0.7.18",
+ "version": "0.7.24",
"license": "APACHE-2.0",
"dependencies": {
"@ungap/with-resolvers": "^0.1.0",
diff --git a/core/package.json b/core/package.json
index e6844e85633..5139b6b4072 100644
--- a/core/package.json
+++ b/core/package.json
@@ -1,6 +1,6 @@
{
"name": "@pyscript/core",
- "version": "0.7.18",
+ "version": "0.7.24",
"type": "module",
"description": "PyScript",
"module": "./index.js",
diff --git a/core/src/plugins/py-editor.js b/core/src/plugins/py-editor.js
index 9fc326a21a5..71c15f31904 100644
--- a/core/src/plugins/py-editor.js
+++ b/core/src/plugins/py-editor.js
@@ -38,7 +38,7 @@ const getRelatedScript = (target, type) => {
return editor?.parentNode?.previousElementSibling;
};
-async function execute({ currentTarget, script }) {
+async function execute({ currentTarget, script }, onBeforeRun = "") {
const { env, pySrc, outDiv } = this;
const hasRunButton = !!currentTarget;
@@ -152,7 +152,8 @@ async function execute({ currentTarget, script }) {
console.error(str);
}
};
- sync.runAsync(pySrc).then(enable, enable);
+ if (onBeforeRun) onBeforeRun += ";";
+ sync.runAsync(onBeforeRun + pySrc).then(enable, enable);
});
}
@@ -176,11 +177,11 @@ const makeRunButton = (handler, type) => {
runButton.innerHTML = RUN_BUTTON;
runButton.setAttribute("aria-label", "Python Script Run Button");
runButton.addEventListener("click", async (event) => {
+ const script = getRelatedScript(runButton, type);
if (
runButton.classList.contains("running") &&
confirm("Stop evaluating this code?")
) {
- const script = getRelatedScript(runButton, type);
if (script) {
const env = script.getAttribute("env");
// remove the bootstrapped env which could be one or shared
@@ -205,7 +206,10 @@ const makeRunButton = (handler, type) => {
return;
}
runButton.blur();
- await handler.handleEvent(event);
+ await handler.handleEvent(
+ event,
+ script?.getAttribute("onbeforerun") || "",
+ );
});
return runButton;
};
@@ -235,12 +239,13 @@ const makeOutDiv = (type) => {
return outDiv;
};
-const makeBoxDiv = (handler, type) => {
+const makeBoxDiv = (handler, type, output) => {
const boxDiv = document.createElement("div");
boxDiv.className = `${type}-editor-box`;
const editorDiv = makeEditorDiv(handler, type);
- const outDiv = makeOutDiv(type);
+ const outDiv = output ? document.getElementById(output) : makeOutDiv(type);
+ if (output) outDiv.classList.add(`${type}-editor-output`);
boxDiv.append(editorDiv, outDiv);
return [boxDiv, outDiv, editorDiv.querySelector("button")];
@@ -276,12 +281,20 @@ const init = async (script, type, interpreter) => {
}).onmessage = ({ target }) => target.terminate();
}
+ // allow bootstrap with same env for repeated editor creation
+ // only if `env-override` is explicitly set as attribute
if (hasConfig && configs.has(env)) {
- throw new SyntaxError(
- configs.get(env)
- ? `duplicated config for env: ${env}`
- : `unable to add a config to the env: ${env}`,
- );
+ if (script.hasAttribute("env-override")) {
+ // in this case we need to bootstrap the env again
+ // because otherwise each env would leak
+ envs.delete(env);
+ } else {
+ throw new SyntaxError(
+ configs.get(env)
+ ? `duplicated config for env: ${env}`
+ : `unable to add a config to the env: ${env}`,
+ );
+ }
}
configs.set(env, hasConfig);
@@ -328,7 +341,7 @@ const init = async (script, type, interpreter) => {
// in every other case be sure that if the listener override returned
// `false` nothing happens, otherwise keep doing what it always did
else {
- context.handleEvent = async (event) => {
+ context.handleEvent = async (event, onBeforeRun) => {
// trap the currentTarget ASAP (if any)
// otherwise it gets lost asynchronously
const { currentTarget } = event;
@@ -338,7 +351,11 @@ const init = async (script, type, interpreter) => {
});
// avoid executing the default handler if the override returned `false`
if ((await callback(event)) !== false)
- await execute.call(context, { currentTarget });
+ await execute.call(
+ context,
+ { currentTarget },
+ onBeforeRun,
+ );
};
}
},
@@ -388,8 +405,7 @@ const init = async (script, type, interpreter) => {
};
if (isSetup) {
- await context.handleEvent({ currentTarget: null, script });
- notifyEditor();
+ context.handleEvent({ currentTarget: null, script }).then(notifyEditor);
return;
}
@@ -411,13 +427,23 @@ const init = async (script, type, interpreter) => {
if (!target.hasAttribute("root")) target.setAttribute("root", target.id);
// @see https://github.com/JeffersGlass/mkdocs-pyscript/blob/main/mkdocs_pyscript/js/makeblocks.js
- const [boxDiv, outDiv, runButton] = makeBoxDiv(context, type);
+ const [boxDiv, outDiv, runButton] = makeBoxDiv(
+ context,
+ type,
+ script.getAttribute("output"),
+ );
boxDiv.dataset.env = script.hasAttribute("env") ? env : interpreter;
const inputChild = boxDiv.querySelector(`.${type}-editor-input > div`);
const parent = inputChild.attachShadow({ mode: "open" });
// avoid inheriting styles from the outer component
- parent.innerHTML = ``;
+ const styles = [":host { all: initial; }"];
+ const rows = script.getAttribute("rows");
+ if (rows) {
+ const maxHeight = Math.floor(parseInt(rows) * 18.5) + "px";
+ styles.push(`.cm-editor { height: auto; max-height: ${maxHeight}; }`);
+ }
+ parent.innerHTML = ``;
target.appendChild(boxDiv);