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******************************************************************************/
632class 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/******************************************************************************
98128Built-in plugins and runtimes.
99129******************************************************************************/
100-
101130class 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/******************************************************************************
193223The core PyScript app definition.
194224******************************************************************************/
195-
196225const 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/******************************************************************************
457507Start PyScript.
458508******************************************************************************/
0 commit comments