8000 add base component file with components base classe and adapt pyrepl … · Positive-Conative/pyscript@95d5026 · GitHub
[go: up one dir, main page]

Skip to content

Commit 95d5026

Browse files
committed
add base component file with components base classe and adapt pyrepl to new base class
1 parent df5b4a4 commit 95d5026

File tree

2 files changed

+174
-68
lines changed

2 files changed

+174
-68
lines changed

pyscriptjs/src/components/base.ts

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import { pyodideLoaded, loadedEnvironments, componentDetailsNavOpen, mode } from '../stores';
2+
3+
// Premise used to connect to the first available pyodide interpreter
4+
let pyodideReadyPromise;
5+
let environments;
6+
let currentMode;
7+
let Element;
8+
9+
pyodideLoaded.subscribe(value => {
10+
pyodideReadyPromise = value;
11+
});
12+
loadedEnvironments.subscribe(value => {
13+
environments = value;
14+
});
15+
16+
let propertiesNavOpen;
17+
componentDetailsNavOpen.subscribe(value => {
18+
propertiesNavOpen = value;
19+
});
20+
21+
mode.subscribe(value => {
22+
currentMode = value;
23+
});
24+
25+
// TODO: use type declaractions
26+
type PyodideInterface = {
27+
registerJsModule(name: string, module: object): void
28+
}
29+
30+
31+
export class BaseEvalElement extends HTMLElement {
32+
shadow: ShadowRoot;
33+
wrapper: HTMLElement;
34+
code: string;
35+
btnConfig: HTMLElement;
36+
btnRun: HTMLElement;
37+
outputElement: HTMLElement; //HTMLTextAreaElement;
38+
theme: string;
39+
40+
constructor() {
41+
super();
42+
43+
// attach shadow so we can preserve the element original innerHtml content
44+
this.shadow = this.attachShadow({ mode: 'open'});
45+
this.wrapper = document.createElement('slot');
46+
this.shadow.appendChild(this.wrapper);
47+
}
48+
49+
addToOutput(s: string) {
50+
this.outputElement.innerHTML += "<div>"+s+"</div>";
51+
this.outputElement.hidden = false;
52+
}
53+
54+
postEvaluate(){
55+
56+
}
57+
58+
getSource(): string{
59+
return "";
60+
}
61+
62+
protected async _register_esm(pyodide: PyodideInterface): Promise<void> {
63+
const imports: {[key: string]: unknown} = {}
64+
65+
for (const node of document.querySelectorAll("script[type='importmap']")) {
66+
const importmap = (() => {
67+
try {
68+
return JSON.parse(node.textContent)
69+
} catch {
70+
return null
71+
}
72+
})()
73+
74+
if (importmap?.imports == null)
75+
continue
76+
77+
for (const [name, url] of Object.entries(importmap.imports)) {
78+
if (typeof name != "string" || typeof url != "string")
79+
continue
80+
81+
try {
82+
// XXX: pyodide doesn't like Module(), failing with
83+
// "can't read 'name' of undefined" at import time
84+
imports[name] = {...await import(url)}
85+
} catch {
86+
console.error(`failed to fetch '${url}' for '${name}'`)
87+
}
88+
}
89+
}
90+
91+
pyodide.registerJsModule("esm", imports)
92+
}
93+
94+
async evaluate() {
95+
console.log('evaluate');
96+
let pyodide = await pyodideReadyPromise;
97+
98+
try {
99+
// @ts-ignore
100+
const source = this.getSource();
101+
await this._register_esm(pyodide)
102+
103+
let output;
104+
105+
if (source.includes("asyncio")){
106+
output = await pyodide.runPythonAsync(source);
107+
await pyodide.runPythonAsync(`output_manager.revert()`)
108+
}else{
109+
output = pyodide.runPython(source);
110+
pyodide.runPython(`output_manager.revert()`)
111+
}
112+
113+
if (output !== undefined){
114+
if (Element === undefined){
115+
Element = pyodide.globals.get('Element');
116+
}
117+
const out = Element(this.outputElement.id);
118+
// @ts-ignore
119+
out.write.callKwargs(output, { append : true});
120+
121+
if (!this.hasAttribute('target')) {
122+
this.outputElement.hidden = false;
123+
}
124+
}
125+
126+
this.postEvaluate()
127+
128+
// if (this.hasAttribute('auto-generate')) {
129+
// let nextExecId = parseInt(this.getAttribute('exec-id')) + 1;
130+
// const newPyRepl = document.createElement("py-repl");
131+
// newPyRepl.setAttribute('root', this.getAttribute('root'));
132+
// newPyRepl.id = this.getAttribute('root') + "-" + nextExecId.toString();
133+
// newPyRepl.setAttribute('auto-generate', null);
134+
// if (this.hasAttribute('target')){
135+
// newPyRepl.setAttribute('target', this.getAttribute('target'));
136+
// }
137+
138+
// newPyRepl.setAttribute('exec-id', nextExecId.toString());
139+
// this.parentElement.appendChild(newPyRepl);
140+
// }
141+
} catch (err) {
142+
this.addToOutput(err);
143+
}
144+
}
145+
}

pyscriptjs/src/components/pyrepl.ts

Lines changed: 29 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { oneDarkTheme } from "@codemirror/theme-one-dark";
88

99
import { pyodideLoaded, loadedEnvironments, componentDetailsNavOpen, currentComponentDetails, mode } from '../stores';
1010
import { addClasses } from '../utils';
11+
import { BaseEvalElement } from './base';
1112

1213
// Premise used to connect to the first available pyodide interpreter
1314
let pyodideReadyPromise;
@@ -43,27 +44,15 @@ function createCmdHandler(el){
4344
}
4445

4546

46-
export class PyRepl extends HTMLElement {
47-
shadow: ShadowRoot;
48-
wrapper: HTMLElement;
47+
export class PyRepl extends BaseEvalElement {
4948
editor: EditorView;
5049
editorNode: HTMLElement;
5150
code: string;
52-
cm: any;
53-
btnConfig: HTMLElement;
54-
btnRun: HTMLElement;
55-
editorOut: HTMLElement; //HTMLTextAreaElement;
5651
theme: string;
57-
// editorState: EditorState;
5852

5953
constructor() {
6054
super();
6155

62-
// attach shadow so we can preserve the element original innerHtml content
63-
this.shadow = this.attachShadow({ mode: 'open'});
64-
65-
this.wrapper = document.createElement('slot');
66-
6756
// add an extra div where we can attach the codemirror editor
6857
this.editorNode = document.createElement('div');
6958
addClasses(this.editorNode, ["editor-box"])
@@ -172,21 +161,21 @@ export class PyRepl extends HTMLElement {
172161
}
173162

174163
if (this.hasAttribute('target')) {
175-
this.editorOut = document.getElementById(this.getAttribute('target'));
164+
this.outputElement = document.getElementById(this.getAttribute('target'));
176165

177166
// in this case, the default output-mode is append, if hasn't been specified
178167
if (!this.hasAttribute('output-mode')) {
179168
this.setAttribute('output-mode', 'append');
180169
}
181170
}else{
182171
// Editor Output Div
183-
this.editorOut = document.createElement('div');
184-
this.editorOut.classList.add("output");
185-
this.editorOut.hidden = true;
186-
this.editorOut.id = this.id + "-" + this.getAttribute("exec-id");
172+
this.outputElement = document.createElement('div');
173+
this.outputElement.classList.add("output");
174+
this.outputElement.hidden = true;
175+
this.outputElement.id = this.id + "-" + this.getAttribute("exec-id");
187176

188177
// add the output div id there's not target
189-
mainDiv.appendChild(this.editorOut);
178+
mainDiv.appendChild(this.outputElement);
190179
}
191180

192181
this.appendChild(mainDiv);
@@ -195,63 +184,35 @@ export class PyRepl extends HTMLElement {
195184
}
196185

197186
addToOutput(s: string) {
198-
this.editorOut.innerHTML += "<div>"+s+"</div>";
199-
this.editorOut.hidden = false;
187+
this.outputElement.innerHTML += "<div>"+s+"</div>";
188+
this.outputElement.hidden = false;
200189
}
201190

202-
async evaluate() {
203-
console.log('evaluate');
204-
let pyodide = await pyodideReadyPromise;
191+
postEvaluate(): void {
192+
if (this.hasAttribute('auto-generate')) {
193+
let nextExecId = parseInt(this.getAttribute('exec-id')) + 1;
194+
const newPyRepl = document.createElement("py-repl");
195+
newPyRepl.setAttribute('root', this.getAttribute('root'));
196+
newPyRepl.id = this.getAttribute('root') + "-" + nextExecId.toString();
197+
newPyRepl.setAttribute('auto-generate', null);
198+
if (this.hasAttribute('target')){
199+
newPyRepl.setAttribute('target', this.getAttribute('target'));
200+
}
201+
202+
newPyRepl.setAttribute('exec-id', nextExecId.toString());
203+
this.parentElement.appendChild(newPyRepl);
204+
}
205+
}
205206

206-
try {
207-
// @ts-ignore
208-
const sourceStrings = [`output_manager.change("`+this.editorOut.id+`")`,
207+
getSource(): string {
208+
const sourceStrings = [`output_manager.change("`+this.outputElement.id+`")`,
209209
...this.editor.state.doc.toString().split("\n")];
210-
const source = sourceStrings.join('\n')
211-
let output;
212-
213-
if (source.includes("asyncio")){
214-
output = await pyodide.runPythonAsync(source);
215-
await pyodide.runPythonAsync(`output_manager.revert()`)
216-
}else{
217-
output = pyodide.runPython(source);
218-
pyodide.runPython(`output_manager.revert()`)
219-
}
220-
221-
if (output !== undefined){
222-
let Element = pyodide.globals.get('Element');
223-
let out = Element(this.editorOut.id);
224-
225-
// @ts-ignore
226-
out.write.callKwargs(output, { append : true});
227-
228-
if (!this.hasAttribute('target')) {
229-
this.editorOut.hidden = false;
230-
}
231-
}
210+
return sourceStrings.join('\n')
211+
}
232212

233-
if (this.hasAttribute('auto-generate')) {
234-
let nextExecId = parseInt(this.getAttribute('exec-id')) + 1;
235-
const newPyRepl = document.createElement("py-repl");
236-
newPyRepl.setAttribute('root', this.getAttribute('root'));
237-
newPyRepl.id = this.getAttribute('root') + "-" + nextExecId.toString();
238-
newPyRepl.setAttribute('auto-generate', null);
239-
if (this.hasAttribute('target')){
240-
newPyRepl.setAttribute('target', this.getAttribute('target'));
241-
}
242-
243-
newPyRepl.setAttribute('exec-id', nextExecId.toString());
244-
this.parentElement.appendChild(newPyRepl);
245-
}
246-
} catch (err) {
247-
this.addToOutput(err);
248-
}
249-
}
250-
251213
render(){
252214
console.log('rendered');
253215

254216
}
255217
}
256218

257-

0 commit comments

Comments
 (0)
0