Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2b7cbe0

Browse files
committed
add array of initializers, to run after the python runtime has loaded
1 parent 3d613b8 commit 2b7cbe0

File tree

5 files changed

+141
-17
lines changed

5 files changed

+141
-17
lines changed

pyscriptjs/src/App.svelte

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import { faPlusCircle } from '@fortawesome/free-solid-svg-icons'
55
import Tailwind from "./Tailwind.svelte";
66
import { loadInterpreter } from './interpreter';
7-
import { pyodideLoaded, loadedEnvironments, navBarOpen, componentsNavOpen, mode, scriptsQueue } from './stores';
7+
import { pyodideLoaded, loadedEnvironments, navBarOpen, componentsNavOpen, mode, scriptsQueue, initializers } from './stores';
88
import Main from "./Main.svelte";
99
import Header from "./Header.svelte";
1010
import SideNav from "./SideNav.svelte";
@@ -47,6 +47,12 @@
4747
for (let script of $scriptsQueue) {
4848
script.evaluate();
4949
}
50+
scriptsQueue.set([])
51+
}
52+
53+
// now we call all initializers AFTER we actually executed all page scripts
54+
for (let initializer of $initializers){
55+
initializer();
5056
}
5157
}
5258

pyscriptjs/src/components/pyrepl.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { keymap, ViewUpdate } from "@codemirror/view";
66
import { defaultKeymap } from "@codemirror/commands";
77
import { oneDarkTheme } from "@codemirror/theme-one-dark";
88

9-
import { pyodideLoaded, loadedEnvironments, componentDetailsNavOpen, currentComponentDetails, mode, addToScriptsQueue } from '../stores';
9+
import { pyodideLoaded, loadedEnvironments, componentDetailsNavOpen, currentComponentDetails, mode } from '../stores';
1010
import { addClasses } from '../utils';
1111

1212
// Premise used to connect to the first available pyodide interpreter
@@ -208,7 +208,7 @@ export class PyRepl extends HTMLElement {
208208
let source = this.editor.state.doc.toString();
209209
let output;
210210
if (source.includes("asyncio")){
211-
output = pyodide.runPythonAsync(source);
211+
output = await pyodide.runPythonAsync(source);
212212
}else{
213213
output = pyodide.runPython(source);
214214
}

pyscriptjs/src/components/pyscript.ts

Lines changed: 87 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ import { keymap, ViewUpdate } from "@codemirror/view";
66
import { defaultKeymap } from "@codemirror/commands";
77
import { oneDarkTheme } from "@codemirror/theme-one-dark";
88

9-
import { pyodideLoaded, loadedEnvironments, componentDetailsNavOpen, currentComponentDetails, mode, addToScriptsQueue } from '../stores';
9+
import { pyodideLoaded, loadedEnvironments, componentDetailsNavOpen, currentComponentDetails, mode, addToScriptsQueue, addInitializer } from '../stores';
1010
import { addClasses } from '../utils';
1111

1212
// Premise used to connect to the first available pyodide interpreter
1313
let pyodideReadyPromise;
1414
let environments;
1515
let currentMode;
16+
let handlersCollected = false;
1617

1718
pyodideLoaded.subscribe(value => {
1819
pyodideReadyPromise = value;
@@ -40,6 +41,46 @@ function createCmdHandler(el){
4041
}
4142

4243

44+
class Script {
45+
source: string;
46+
state: string;
47+
target: string;
48+
49+
constructor(source: string, target: string) {
50+
this.target = target;
51+
this.source = source;
52+
this.state = 'waiting';
53+
}
54+
55+
async evaluate() {
56+
console.log('evaluate');
57+
let pyodide = await pyodideReadyPromise;
58+
// debugger
59+
try {
60+
// @ts-ignore
61+
// let source = this.editor.state.doc.toString();
62+
let output;
63+
if (this.source.includes("asyncio")){
64+
output = await pyodide.runPythonAsync(this.source);
65+
}else{
66+
output = pyodide.runPython(this.source);
67+
}
68+
69+
if (this.target){
70+
// this.editorOut.innerHTML = s;
71+
}
72+
// if (output !== undefined){
73+
// this.addToOutput(output);
74+
// }
75+
76+
77+
} catch (err) {
78+
console.log("OOOPS, this happened: " + err);
79+
// this.addToOutput(err);
80+
}
81+
}
82+
}
83+
4384
export class PyScript extends HTMLElement {
4485
shadow: ShadowRoot;
4586
wrapper: HTMLElement;
@@ -176,11 +217,10 @@ export class PyScript extends HTMLElement {
176217
let source = this.editor.state.doc.toString();
177218
let output;
178219
if (source.includes("asyncio")){
179-
output = pyodide.runPythonAsync(source);
220+
output = await pyodide.runPythonAsync(source);
180221
}else{
181222
output = pyodide.runPython(source);
182223
}
183-
184224
if (output !== undefined){
185225
this.addToOutput(output);
186226
}
@@ -200,3 +240,47 @@ export class PyScript extends HTMLElement {
200240

201241
}
202242
}
243+
244+
async function initHandlers() {
245+
if( handlersCollected == true ) return;
246+
247+
console.log('Collecting nodes...');
248+
let pyodide = await pyodideReadyPromise;
249+
let matches : NodeListOf<HTMLElement> = document.querySelectorAll('[pys-onClick]');
250+
let output;
251+
let source;
252+
for (var el of matches) {
253+
let handlerCode = el.getAttribute('pys-onClick');
254+
source = `Element("${ el.id }").element.onclick = ${ handlerCode }`;
255+
output = await pyodide.runPythonAsync(source);
256+
257+
// el.onclick = (evt: any) => {
258+
// console.log("click");
259+
// new Promise((resolve, reject) => {
260+
// setTimeout(() => {
261+
// console.log('Inside')
262+
// }, 300);
263+
// }).then(() => {
264+
// console.log("resolved")
265+
// });
266+
// // let handlerCode = el.getAttribute('pys-onClick');
267+
// // pyodide.runPython(handlerCode);
268+
// }
269+
}
270+
handlersCollected = true;
271+
272+
matches = document.querySelectorAll('[pys-onKeyDown]');
273+
for (var el of matches) {
274+
let handlerCode = el.getAttribute('pys-onKeyDown');
275+
source = `Element("${ el.id }").element.addEventListener("keydown", ${ handlerCode })`;
276+
output = await pyodide.runPythonAsync(source);
277+
}
278+
}
279+
addInitializer(initHandlers)
280+
281+
// if( document.readyState === 'loading' ) {
282+
// document.addEventListener( 'DOMContentLoaded', initHandlers );
283+
// }
284+
// else if( document.readyState === 'interactive' || document.readyState === 'complete' ) {
285+
// initHandlers();
286+
// }

pyscriptjs/src/interpreter.ts

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,30 +47,54 @@ pyscript = PyScript()
4747
4848
4949
class Element:
50-
def __init__(self, element_id):
50+
def __init__(self, element_id, element=None):
5151
self._id = element_id
52+
self._element = element
5253
5354
@property
5455
def element(self):
5556
"""Return the dom element"""
56-
return document.querySelector(f'#{self._id}');
57+
if not self._element:
58+
self._element = document.querySelector(f'#{self._id}');
59+
return self._element
5760
5861
def write(self, value, append=False):
5962
console.log(f"Element.write: {value} --> {append}")
63+
# TODO: it should be the opposite... pyscript.write should use the Element.write
64+
# so we can consolidate on how we write depending on the element type
6065
pyscript.write(self._id, value, append=append)
6166
6267
def clear(self):
63-
self.write("", append=False)
68+
if hasattr(self.element, 'value'):
69+
self.element.value = ''
70+
else:
71+
self.write("", append=False)
72+
73+
def select(self, query, from_content=False):
74+
el = self.element
75+
if from_content:
76+
el = el.content
6477
65-
def clone(self, new_id=None):
78+
_el = el.querySelector(query)
79+
if _el:
80+
return Element(_el.id, _el)
81+
else:
82+
console.log(f"WARNING: can't find element matching query {query}")
83+
84+
def clone(self, new_id=None, to=None):
6685
if new_id is None:
6786
new_id = self.element.id
6887
69-
clone = self.element.cloneNode(true);
88+
clone = self.element.cloneNode(True);
7089
clone.id = new_id;
7190
91+
if to:
92+
to.element.appendChild(clone)
93+
7294
# Inject it into the DOM
7395
self.element.after(clone);
96+
97+
return Element(clone.id, clone)
7498
7599
`
76100

@@ -81,13 +105,13 @@ let loadInterpreter = async function(): any {
81105
});
82106

83107
// now that we loaded, add additional convenience fuctions
84-
pyodide.loadPackage(['matplotlib', 'numpy'])
108+
// pyodide.loadPackage(['matplotlib', 'numpy'])
85109

86110
await pyodide.loadPackage("micropip");
87-
await pyodide.runPythonAsync(`
88-
import micropip
89-
await micropip.install("ipython")
90-
`);
111+
// await pyodide.runPythonAsync(`
112+
// import micropip
113+
// await micropip.install("ipython")
114+
// `);
91115

92116
let output = pyodide.runPython(additional_definitions);
93117

pyscriptjs/src/stores.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ export const mainDiv = writable(null);
2323
export const currentComponentDetails = writable([]);
2424
export const mode = writable(DEFAULT_MODE)
2525
export const scriptsQueue = writable([])
26+
export const initializers = writable([])
2627

27-
let scriptsQueue_ = []
28+
let scriptsQueue_ = [];
29+
let initializers_ = [];
2830

2931
scriptsQueue.subscribe(value => {
3032
scriptsQueue_ = value;
@@ -33,3 +35,11 @@ scriptsQueue.subscribe(value => {
3335
export const addToScriptsQueue = (script) => {
3436
scriptsQueue.set([...scriptsQueue_, script]);
3537
};
38+
39+
scriptsQueue.subscribe(value => {
40+
scriptsQueue_ = value;
41+
});
42+
43+
export const addInitializer = (initializer) => {
44+
initializers.set([...initializers_, initializer]);
45+
};

0 commit comments

Comments
 (0)