Skip to content
This repository was archived by the owner on Sep 21, 2023. It is now read-only.

Commit f82c9cc

Browse files
committed
Tidy ups
1 parent 813fafa commit f82c9cc

File tree

1 file changed

+95
-45
lines changed

1 file changed

+95
-45
lines changed

pyscript.js

Lines changed: 95 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,33 @@
11
"use strict";
2+
/******************************************************************************
3+
MicroPyscript.
4+
5+
A small, simple, single file kernel of PyScript, made for testing purposes.
6+
7+
See the README for more details, design decisions, and an explanation of how
8+
things work.
9+
10+
Authors:
11+
- Nicholas H.Tollervey (ntollervey@anaconda.org)
12+
13+
Copyright (c) 2022 Anaconda Inc.
14+
15+
Licensed under the Apache License, Version 2.0 (the "License");
16+
you may not use this file except in compliance with the License.
17+
You may obtain a copy of the License at
18+
19+
http://www.apache.org/licenses/LICENSE-2.0
20+
21+
Unless required by applicable law or agreed to in writing, software
22+
distributed under the License is distributed on an "AS IS" BASIS,
23+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24+
See the License for the specific language governing permissions and
25+
limitations under the License.
26+
******************************************************************************/
27+
228

329
/******************************************************************************
4-
Base classes.
30+
Base classes and constants.
531
******************************************************************************/
632
class Plugin {
733
/*
@@ -94,32 +120,34 @@ class Runtime {
94120
}
95121
}
96122

123+
124+
const splashInnerHTML = '<svg class="whole" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg" height="48" width="48"><g id="loader"><animateTransform xlink:href="#loader" attributeName="transform" attributeType="XML" type="rotate" from="0 50 50" to="360 50 50" dur="1s" begin="0s" repeatCount="indefinite" restart="always"></animateTransform><path class="a" opacity="0.2" fill-rule="evenodd" clip-rule="evenodd" d="M50 100C77.6142 100 100 77.6142 100 50C100 22.3858 77.6142 0 50 0C22.3858 0 0 22.3858 0 50C0 77.6142 22.3858 100 50 100ZM50 90C72.0914 90 90 72.0914 90 50C90 27.9086 72.0914 10 50 10C27.9086 10 10 27.9086 10 50C10 72.0914 27.9086 90 50 90Z" fill="#999999"></path><path class="b" fill-rule="evenodd" clip-rule="evenodd" d="M100 50C100 22.3858 77.6142 0 50 0V10C72.0914 10 90 27.9086 90 50H100Z" fill="#999999"></path></g></svg>';
125+
126+
97127
/******************************************************************************
98128
Built-in plugins and runtimes.
99129
******************************************************************************/
100-
101130
class PyScriptTag extends Plugin {
102131
start(config) {
103132
// Define the PyScript element.
104133
class PyScript extends HTMLElement {
105134
connectedCallback() {
106135
/*
107-
All code is dispatched as a "py-code" event with code for later
108-
processing.
136+
All code is dispatched as a py-script-registered event
137+
for later processing.
109138
110139
Additional metadata if available:
111-
- this element's id
112-
- the src value
140+
- the src value for remote source file
141+
- this element as target
113142
*/
114-
var code = this.textContent;
143+
const code = this.textContent;
115144
this.textContent = "";
116-
var detail = {}
117-
detail.code = code.trim() ? code : "";
118-
if (this.attributes.src) {
119-
detail.src = this.attributes.src.value;
120-
}
121-
detail.target = this;
122-
const pyScriptRegistered = new CustomEvent("py-script-registered", {"detail": detail});
145+
const script = {
146+
code: code.trim() ? code : "",
147+
src: this.attributes.src ? this.attributes.src.value : "",
148+
target: this
149+
};
150+
const pyScriptRegistered = new CustomEvent("py-script-registered", {"detail": script});
123151
document.dispatchEvent(pyScriptRegistered);
124152
}
125153
}
@@ -146,6 +174,7 @@ class MicroPythonRuntime extends Runtime {
146174
if(config.mp_memory) {
147175
mp_memory = config.mp_memory;
148176
}
177+
// TODO: Fix this.
149178
mp_js_stdout.addEventListener('print', function(e) {
150179
this.innerText = this.innerText + e.data;
151180
}, false);
@@ -189,28 +218,33 @@ class CPythonRuntime extends Runtime {
189218
}
190219
}
191220

221+
192222
/******************************************************************************
193223
The core PyScript app definition.
194224
******************************************************************************/
195-
196225
const main = function() {
197226
// Really simple logging. Emoji 🐍 highlights PyScript app logs. ;-)
198227
const logger = function() {
199228
return Function.prototype.bind.call(console.log, console, "🐍 ", ...arguments);
200229
}();
201230
logger("Starting PyScript. 👋")
231+
202232
// Default configuration settings for PyScript. These may be overridden by
203233
// the app.loadConfig function.
204234
const config = {
205235
"runtime": "micropython" // Numpty default.
206236
}
237+
207238
// Contains plugins to the PyScript context.
208239
const plugins = [];
240+
209241
// Contains Python scripts found on the page.
210242
const scripts = [];
243+
211244
// Contains Python scripts whose source code is available, and pending
212245
// evaluation by the runtime.
213246
const pendingScripts = [];
247+
214248
// Details of runtimes.
215249
// Key: lowercase runtime name.
216250
// Value: the class wrapping that version of the runtime.
@@ -220,9 +254,11 @@ const main = function() {
220254
}
221255
// Default to smallest/fastest runtime.
222256
runtimes["default"] = runtimes["micropython"]
257+
223258
// Eventually references an instance of the Runtime class, representing the
224259
// started runtime.
225260
let runtime = null;
261+
226262
// Flag to indicate the runtime is ready to evaluate scripts.
227263
let runtimeReady = false;
228264

@@ -298,15 +334,15 @@ const main = function() {
298334
},
299335
runtimeStarted: function() {
300336
/*
301-
The runtime is ready to go, so flip the runtimeReady flag and begin
337+
The runtime is ready to go, so flip the runtimeReady flag, step
338+
through each registered plugin's onRuntimeReady method, and begin
302339
evaluating any code in the pendingScripts queue.
303340
*/
304341
logger(`Runtime started. 🎬`)
305342
runtimeReady = true;
306343
plugins.forEach(function(plugin) {
307-
plugin.onRuntimeReady(config);
344+
plugin.onRuntimeReady(config, runtime);
308345
});
309-
pendingScripts.reverse();
310346
pendingScripts.forEach(function(script) {
311347
const pyEvalScript = new CustomEvent("py-eval-script", {detail: script});
312348
document.dispatchEvent(pyEvalScript);
@@ -316,8 +352,8 @@ const main = function() {
316352
},
317353
registerScript(script) {
318354
/*
319-
Add a Python script to the scripts array, to be run when the
320-
runtime is ready.
355+
Add a Python script to the scripts array. If required load the code
356+
by fetching it from the URL found in the script's src attribute.
321357
*/
322358
// Ignore code that is just whitespace.
323359
script.code = script.code.trim() ? script.code : "";
@@ -331,7 +367,7 @@ const main = function() {
331367
// Handle asynchronous loading of the script's code from the
332368
// URL in src.
333369
fetch(script.src).then(function(response) {
334-
logger(`Fetch script from "${script.src}" 📡`, response);
370+
logger(`Fetched script from "${script.src}" 📡`, response);
335371
if (response.ok) {
336372
response.text().then((data) => {
337373
script.code = data;
@@ -347,14 +383,14 @@ const main = function() {
347383
} else {
348384
// Warn that a script has no source code either inline or via
349385
// the src attribute.
350-
logger("Script has no source code. ⁉️", script);
386+
logger("Script has no source code. ⁉️😕", script);
351387
}
352388
},
353389
loadScript(script) {
354390
/*
355-
Ensure the source code for all the scripts is available. For any
356-
code that has a src but no content, will fetch the code from the
357-
URL in src. Dispatches a py-scripts-loaded event when done.
391+
The given script is either queued for later evaluation if the
392+
runtime isn't ready yet, or the py-eval-script event is
393+
dispatched so the runtime can evaluate it.
358394
*/
359395
if (runtimeReady) {
360396
// Runtime is ready, so evaluate the code.
@@ -376,19 +412,22 @@ const main = function() {
376412
},
377413
}
378414

379-
// The following functions are used to coordinate the unfolding of PyScript
380-
// as various events are dispatched and state evolves to trigger the next
381-
// steps.
415+
416+
// The following functions coordinate the unfolding of PyScript as various
417+
// events are dispatched and state evolves to trigger the next steps.
382418
//
383419
// These functions are defined in the order they're roughly expected to
384420
// be called through the life-cycle of the page, although this cannot be
385421
// guaranteed for some of the functions.
386-
387422
function onPyConfigured(e) {
388423
/*
389-
Once configured, load the runtime, register the default plugins
390-
(currently only the PyScriptTag), freeze the config and start the
391-
plugins to kick off extracting Python scripts from the page.
424+
Once PyScript has loaded its configuration:
425+
- register the default plugins (currently only PyScriptTag), so
426+
they can modify the config if required.
427+
- freeze the config so it can't be changed from this point.
428+
- load the Python runtime into the browser.
429+
- start the plugins to kick off extracting Python scripts from the
430+
page.
392431
*/
393432
app.registerPlugin(new PyScriptTag());
394433
Object.freeze(config);
@@ -398,32 +437,42 @@ const main = function() {
398437
}
399438
document.addEventListener("py-configured", onPyConfigured);
400439

440+
401441
function onPyScriptRegistered(e) {
402442
/*
403-
Register a Python script and related metadatacontained in the
404-
dispatched event's detail.
443+
A plugin has, in some way, detected a Python script definition.
444+
445+
Register metadata about the script via the dispatched event's detail.
405446
*/
406447
app.registerScript(e.detail);
407448
}
408449
document.addEventListener("py-script-registered", onPyScriptRegistered);
409450

451+
410452
function onPyScriptLoaded(e) {
411453
/*
412-
The source of a Python script is available as metadata in the
413-
dispatched event's detail.
454+
The source of a Python script has been obtained either as inline code
455+
or as the content of a remote Python source file that has been fetched
456+
over the network.
457+
458+
The source code is included as metadata in the dispatched event's
459+
detail. So signal to the app the script is fully loaded.
414460
*/
415461
app.loadScript(e.detail);
416462
}
417463
document.addEventListener("py-script-loaded", onPyScriptLoaded);
418464

465+
419466
function onRuntimeLoaded(e) {
420467
/*
421-
The runtime has loaded.
468+
The runtime has loaded over the network. Next, start the runtime in
469+
this PyScript context.
422470
*/
423471
app.startRuntime();
424472
}
425473
document.addEventListener("py-runtime-loaded", onRuntimeLoaded);
426474

475+
427476
function onRuntimeReady(e) {
428477
/*
429478
The runtime is ready to evaluate scripts.
@@ -432,27 +481,28 @@ const main = function() {
432481
}
433482
document.addEventListener("py-runtime-ready", onRuntimeReady);
434483

484+
435485
function onEvalScript(e) {
436486
/*
437-
The runtime is ready, and a script's source code is ready, so evaluate
438-
the script with the runtime!
487+
Handle the event designating a script is ready to be evaluated by the
488+
runtime.
439489
*/
440490
app.evaluateScript(e.detail)
441491
}
442492
document.addEventListener("py-eval-script", onEvalScript);
443493

444-
// Finally, return a function to start PyScript.
445494

495+
// Finally, return a function to start PyScript.
446496
return function() {
447-
/*
448-
Start PyScript.
449-
*/
450-
// TODO: check test/debug flag.
451-
app.loadConfig();
497+
// Check to bypass loadConfig, for testing purposes.
498+
if (!window.pyscriptTest) {
499+
app.loadConfig();
500+
}
452501
return app;
453502
}
454503
}();
455504

505+
456506
/******************************************************************************
457507
Start PyScript.
458508
******************************************************************************/

0 commit comments

Comments
 (0)