From 5ec85695b9279a06ea736eb8248fbc3904da51a5 Mon Sep 17 00:00:00 2001 From: Fabio Pliger Date: Fri, 1 Apr 2022 10:45:52 -0500 Subject: [PATCH] add initializers that run before py-script scripts run and post initializers that run after. Also add function to unescape some of the characters when read form html tags --- pyscriptjs/src/App.svelte | 13 ++++++--- pyscriptjs/src/components/pyscript.ts | 38 +++++++++++++++++++-------- pyscriptjs/src/interpreter.ts | 2 +- pyscriptjs/src/stores.ts | 18 +++++++++++++ 4 files changed, 55 insertions(+), 16 deletions(-) diff --git a/pyscriptjs/src/App.svelte b/pyscriptjs/src/App.svelte index 3f67fbf..c98e357 100644 --- a/pyscriptjs/src/App.svelte +++ b/pyscriptjs/src/App.svelte @@ -4,7 +4,7 @@ import { faPlusCircle } from '@fortawesome/free-solid-svg-icons' import Tailwind from "./Tailwind.svelte"; import { loadInterpreter } from './interpreter'; - import { pyodideLoaded, loadedEnvironments, navBarOpen, componentsNavOpen, mode, scriptsQueue, initializers } from './stores'; + import { pyodideLoaded, loadedEnvironments, navBarOpen, componentsNavOpen, mode, scriptsQueue, initializers, postInitializers } from './stores'; import Main from "./Main.svelte"; import Header from "./Header.svelte"; import SideNav from "./SideNav.svelte"; @@ -42,16 +42,21 @@ showNavBar = value; }); + // now we call all initializers before we actually executed all page scripts + for (let initializer of $initializers){ + initializer(); + } + // now we can actually execute the page scripts if we are in play mode if ($mode == "play"){ for (let script of $scriptsQueue) { script.evaluate(); } - scriptsQueue.set([]) + scriptsQueue.set([]); } - // now we call all initializers AFTER we actually executed all page scripts - for (let initializer of $initializers){ + // now we call all post initializers AFTER we actually executed all page scripts + for (let initializer of $postInitializers){ initializer(); } } diff --git a/pyscriptjs/src/components/pyscript.ts b/pyscriptjs/src/components/pyscript.ts index b3864d1..572fbdc 100644 --- a/pyscriptjs/src/components/pyscript.ts +++ b/pyscriptjs/src/components/pyscript.ts @@ -6,7 +6,7 @@ import { keymap, ViewUpdate } from "@codemirror/view"; import { defaultKeymap } from "@codemirror/commands"; import { oneDarkTheme } from "@codemirror/theme-one-dark"; -import { pyodideLoaded, loadedEnvironments, componentDetailsNavOpen, currentComponentDetails, mode, addToScriptsQueue, addInitializer } from '../stores'; +import { pyodideLoaded, loadedEnvironments, componentDetailsNavOpen, currentComponentDetails, mode, addToScriptsQueue, addInitializer, addPostInitializer } from '../stores'; import { addClasses } from '../utils'; // Premise used to connect to the first available pyodide interpreter @@ -40,6 +40,10 @@ function createCmdHandler(el){ return toggleCheckbox } +function htmlDecode(input) { + var doc = new DOMParser().parseFromString(input, "text/html"); + return doc.documentElement.textContent; +} class Script { source: string; @@ -214,7 +218,7 @@ export class PyScript extends HTMLElement { // debugger try { // @ts-ignore - let source = this.editor.state.doc.toString(); + let source = htmlDecode(this.editor.state.doc.toString()); let output; if (source.includes("asyncio")){ output = await pyodide.runPythonAsync(source); @@ -232,6 +236,7 @@ export class PyScript extends HTMLElement { } } catch (err) { this.addToOutput(err); + console.log(err); } } @@ -241,9 +246,8 @@ export class PyScript extends HTMLElement { } } +/** Initialize all elements with py-onClick handlers attributes */ async function initHandlers() { - if( handlersCollected == true ) return; - console.log('Collecting nodes...'); let pyodide = await pyodideReadyPromise; let matches : NodeListOf = document.querySelectorAll('[pys-onClick]'); @@ -254,6 +258,7 @@ async function initHandlers() { source = `Element("${ el.id }").element.onclick = ${ handlerCode }`; output = await pyodide.runPythonAsync(source); + // TODO: Should we actually map handlers in JS instaed of Python? // el.onclick = (evt: any) => { // console.log("click"); // new Promise((resolve, reject) => { @@ -276,11 +281,22 @@ async function initHandlers() { output = await pyodide.runPythonAsync(source); } } -addInitializer(initHandlers) -// if( document.readyState === 'loading' ) { -// document.addEventListener( 'DOMContentLoaded', initHandlers ); -// } -// else if( document.readyState === 'interactive' || document.readyState === 'complete' ) { -// initHandlers(); -// } +/** Mount all elements with attribute py-mount into the Python namespace */ +async function mountElements() { + console.log('Collecting nodes to be mounted into python namespace...'); + let pyodide = await pyodideReadyPromise; + let matches : NodeListOf = document.querySelectorAll('[py-mount]'); + let output; + let source = ""; + for (var el of matches) { + let mountName = el.getAttribute('py-mount'); + if (!mountName){ + mountName = el.id.replace("-", "_"); + } + source += `\n${ mountName } = Element("${ el.id }")`; + } + await pyodide.runPythonAsync(source); +} +addPostInitializer(initHandlers); +addInitializer(mountElements); diff --git a/pyscriptjs/src/interpreter.ts b/pyscriptjs/src/interpreter.ts index f9bf92d..90f0a3d 100644 --- a/pyscriptjs/src/interpreter.ts +++ b/pyscriptjs/src/interpreter.ts @@ -107,7 +107,7 @@ let loadInterpreter = async function(): any { }); // now that we loaded, add additional convenience fuctions - pyodide.loadPackage(['matplotlib', 'numpy']) + pyodide.loadPackage(['matplotlib', 'numpy', 'bokeh']) await pyodide.loadPackage("micropip"); // await pyodide.runPythonAsync(` diff --git a/pyscriptjs/src/stores.ts b/pyscriptjs/src/stores.ts index a795531..c7c8508 100644 --- a/pyscriptjs/src/stores.ts +++ b/pyscriptjs/src/stores.ts @@ -24,9 +24,11 @@ export const currentComponentDetails = writable([]); export const mode = writable(DEFAULT_MODE) export const scriptsQueue = writable([]) export const initializers = writable([]) +export const postInitializers = writable([]) let scriptsQueue_ = []; let initializers_ = []; +let postInitializers_ = []; scriptsQueue.subscribe(value => { scriptsQueue_ = value; @@ -40,6 +42,22 @@ scriptsQueue.subscribe(value => { scriptsQueue_ = value; }); +initializers.subscribe(value => { + initializers_ = value; +}); + export const addInitializer = (initializer) => { + console.log("adding initializer", initializer); initializers.set([...initializers_, initializer]); + console.log("adding initializer", initializer); +}; + +postInitializers.subscribe(value => { + postInitializers_ = value; +}); + +export const addPostInitializer = (initializer) => { + console.log("adding post initializer", initializer); + postInitializers.set([...postInitializers_, initializer]); + console.log("adding post initializer", initializer); };