Skip to content

Commit b9cf9ec

Browse files
committed
WiP
1 parent af47c01 commit b9cf9ec

File tree

6 files changed

+243
-9
lines changed

6 files changed

+243
-9
lines changed

docs/beginning-pyscript.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ module in the document's `<head>` tag:
106106
<meta charset="utf-8" />
107107
<meta name="viewport" content="width=device-width,initial-scale=1" />
108108
<title>🦜 Polyglot - Piratical PyScript</title>
109-
<link rel="stylesheet" href="https://pyscript.net/releases/2024.3.1/core.css">
110-
<script type="module" src="https://pyscript.net/releases/2024.3.1/core.js"></script>
109+
<link rel="stylesheet" href="https://pyscript.net/releases/2024.3.2/core.css">
110+
<script type="module" src="https://pyscript.net/releases/2024.3.2/core.js"></script>
111111
</head>
112112
<body>
113113

@@ -157,8 +157,8 @@ In the end, our HTML should look like this:
157157
<meta charset="utf-8" />
158158
<meta name="viewport" content="width=device-width,initial-scale=1" />
159159
<title>🦜 Polyglot - Piratical PyScript</title>
160-
<link rel="stylesheet" href="https://pyscript.net/releases/2024.3.1/core.css">
161-
<script type="module" src="https://pyscript.net/releases/2024.3.1/core.js"></script>
160+
<link rel="stylesheet" href="https://pyscript.net/releases/2024.3.2/core.css">
161+
<script type="module" src="https://pyscript.net/releases/2024.3.2/core.js"></script>
162162
</head>
163163
<body>
164164
<h1>Polyglot 🦜 💬 🇬🇧 ➡️ 🏴‍☠️</h1>

docs/user-guide/dom.md

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,3 +253,237 @@ paragraphs.style['background-color'] = 'lightyellow'
253253
a collection by setting the proper CSS rules, using `style` with the same API as a dictionary.
254254
* `html`: allows to change the `html` attribute on all the elements of a collection.
255255
* `value`: allows to change the `value` attribute on all the elements of a collection.
256+
257+
## Working with JavaScript
258+
259+
There are three ways in which JavaScript can get into a web page.
260+
261+
1. As a global reference attached to the `window` object in the web page
262+
because the code was referenced as the source of a `script` tag in your HTML
263+
(the very old school way to do this).
264+
2. Using the [Universal Module Definition](https://github.com/umdjs/umd) (UMD)
265+
- an out-of-date and non-standard way to create JavaScript modules.
266+
3. As a standard
267+
[JavaScript Module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules)
268+
which is the modern, standards compliant way to define and use a JavaScript
269+
module. If possible, this is the way you should do things.
270+
271+
Sadly, this being the messy world of the web, methods 1 and 2 are still quite
272+
common, and so you need to know about them so you're able to discern and work
273+
around them. There's nothing WE can do about this situation, but we can
274+
suggest "best practice" ways to work around each situation.
275+
276+
Remember, as mentioned
277+
[elsewhere in our documentation](../configuration/#javascript-modules),
278+
the standard way to get JavaScript modules into your PyScript Python context is
279+
to link a _source_ standard JavaScript module to a _destination_ name:
280+
281+
```toml title="Reference a JavaScript module in the configuration."
282+
[js_modules.main]
283+
"https://cdn.jsdelivr.net/npm/[email protected]/dist/leaflet-src.esm.js" = "leaflet"
284+
```
285+
286+
Then, reference the module via the destination name in your Python code, by
287+
importing it from the `pyscript.js_modules` namespace:
288+
289+
```python title="Import the JavaScript module into Python"
290+
from pyscript.js_modules import leaflet as L
291+
292+
map = L.map("map")
293+
294+
# etc....
295+
```
296+
297+
We'll deal with each of the potential JavaScript related situations in turn:
298+
299+
### JavaScript as a global reference
300+
301+
In this situation, you have some JavaScript code that just globally defines
302+
"stuff" in the context of your web page via a `script` tag. Your HTML will
303+
contain something like this:
304+
305+
```html title="JavaScript as a global reference"
306+
<!doctype html>
307+
<!--
308+
This JS utility escapes and unescapes HTML chars. It adds an "html" object to
309+
the global context.
310+
-->
311+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/index.js"></script>
312+
313+
<!--
314+
Vanilla JS just to check the expected object is in the global context of the
315+
web page.
316+
-->
317+
<script>
318+
console.log(html);
319+
</script>
320+
```
321+
322+
When you find yourself in this situation, simply use the `window` object in
323+
your Python code (found in the `pyscript` namespace) to interact with the
324+
resulting JavaScript objects:
325+
326+
```python title="Python interaction with the JavaScript global reference"
327+
from pyscript import window, document
328+
329+
330+
# The window object is the global context of your web page.
331+
html = window.html
332+
333+
# Just use the object "as usual"...
334+
# e.g. show escaped HTML in the body: &lt;&gt;
335+
document.body.append(html.escape("<>"))
336+
```
337+
338+
You can find an example of this technique here:
339+
340+
[https://pyscript.com/@agiammarchi/floral-glade/v1](https://pyscript.com/@agiammarchi/floral-glade/v1)
341+
342+
### JavaScript as a non-standard UMD module
343+
344+
Sadly, these sorts of non-standard JavaScript modules are still quite
345+
prevalent. But the good news is there are strategies you can use to help you
346+
get them to work properly.
347+
348+
The non-standard UMD approach tries to check for `export` and `module` fields
349+
in the JavaScript module and, if it doesn’t find them, falls back to treating
350+
the module in the same way as a global reference described above.
351+
352+
If you find you have a UMD JavaScript module, there are services online to
353+
automagically convert it to the modern and standards compliant way to d
354+
o JavaScript modules. A common (and usually reliable) service is provided by
355+
[https://esm.run/your-module-name](https://esm.run/your-module-name), a
356+
service that provides an out of the box way to consume the module in the
357+
correct and standard manner:
358+
359+
```html title="Use esm.run to automatically convert a non-standard UMD module"
360+
<!doctype html>
361+
<script type="module">
362+
// this utility escapes and unescape HTML chars
363+
import { escape, unescape } from "https://esm.run/html-escape";
364+
// esm.run returns a module ^^^^^^^^^^^^^^^^^^^^^^^^^^^
365+
console.log(escape("<>"));
366+
// log: "&lt;&gt;"
367+
</script>
368+
```
369+
370+
If a similar test works for the module you want to use, use the esm.run CDN
371+
service within the `py` or `mpy` configuration file as explained at the start
372+
of this section on JavaScript (i.e. you'll use it via the `pyscript.js_modules`
373+
namespace).
374+
375+
If this doesn't work, assume the module is not updated nor migrated to a state
376+
that can be automatically translated by services like esm.run. You could try an
377+
alternative (more modern) JavaScript module to achieve you ends or (if it
378+
really must be this module), you can wrap it in a new JavaScript module that
379+
conforms to the modern standards.
380+
381+
The following four files demonstrate this approach:
382+
383+
```html title="index.html - still grab the script so it appears as a global reference."
384+
<!doctype html>
385+
...
386+
<!-- land the utility still globally as generic script -->
387+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/index.js"></script>
388+
...
389+
```
390+
391+
```js title="wrapper.js - this grabs the JavaScript functionality from the global context and wraps it (exports it) in the modern standards compliant manner."
392+
// get all utilities needed from the global.
393+
const { escape, unescape } = globalThis.html;
394+
395+
// export utilities like a standards compliant module would do.
396+
export { escape, unescape };
397+
```
398+
399+
```toml title="pyscript.toml - configure your JS modules as before, but use your wrapper instead of the original module."
400+
[js_modules.main]
401+
# will simulate a standard JS module
402+
"./wrapper.js" = "html_escaper"
403+
```
404+
405+
```python title="main.py - just import the module as usual and make use of it."
406+
from pyscript import document
407+
408+
# import the module either via
409+
from pyscript.js_modules import html_escaper
410+
# or via
411+
from pyscript.js_modules.html_escaper import escape, unescape
412+
413+
# show on body: &lt;&gt;
414+
document.body.append(html.escape("<>"))
415+
```
416+
417+
You can see this approach in action here:
418+
419+
[https://pyscript.com/@agiammarchi/floral-glade/v2](https://pyscript.com/@agiammarchi/floral-glade/v2)
420+
421+
### A standard JavaScript module
422+
423+
This is both the easiest and best way to import any standard JS module into
424+
Python.
425+
426+
You don't need to reference the script in your HTML, just define how the source
427+
JavaScript module maps into the `pyscript.js_modules` namespace in your
428+
configuration file, as explained above.
429+
430+
That's it!
431+
432+
Here is an example project that uses this approach:
433+
434+
[https://pyscript.com/@agiammarchi/floral-glade/v3](https://pyscript.com/@agiammarchi/floral-glade/v3)
435+
436+
437+
### My own JavaScript code
438+
439+
If you have your own JavaScript work, just remember to write it as a standard
440+
JavaScript module. Put simply, ensure you `export` the things you need to. For
441+
instance, in the following fragment of JavaScript, the two functions are
442+
exported from the module:
443+
444+
```js title="code.js - containing two functions exported as capabilities of the module."
445+
/*
446+
Some simple JavaScript functions for example purposes.
447+
*/
448+
449+
export function hello(name) {
450+
return "Hello " + name;
451+
}
452+
453+
export function fibonacci(n) {
454+
if (n == 1) return 0;
455+
if (n == 2) return 1;
456+
return fibonacci(n - 1) + fibonacci(n - 2);
457+
}
458+
```
459+
460+
Next, just reference this module in the usual way in your TOML or JSON
461+
configuration file:
462+
463+
```TOML title="pyscript.toml - references the code.js module so it will appear as the code module in the pyscript.js_modules namespace."
464+
[js_modules.main]
465+
"code.js" = "code"
466+
```
467+
468+
In your HTML, reference your Python script with this configuration file:
469+
470+
```html title="Reference the expected configuration file."
471+
<script type="py" src="./main.py" config="./pyscript.toml" terminal></script>
472+
```
473+
474+
Finally, just use your JavaScript module’s exported functions inside PyScript:
475+
476+
```python title="Just call your bespoke JavaScript code from Python."
477+
from pyscript.js_modules import code
478+
479+
480+
# Just use the JS code from Python "as usual".
481+
greeting = code.hello("Chris")
482+
print(greeting)
483+
result = code.fibonacci(12)
484+
print(result)
485+
```
486+
487+
You can see this in action in the following example project:
488+
489+
[https://pyscript.com/@ntoll/howto-javascript/latest](https://pyscript.com/@ntoll/howto-javascript/latest)

docs/user-guide/first-steps.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ CSS:
2020
<meta charset="UTF-8">
2121
<meta name="viewport" content="width=device-width,initial-scale=1.0">
2222
<!-- PyScript CSS -->
23-
<link rel="stylesheet" href="https://pyscript.net/releases/2024.3.1/core.css">
23+
<link rel="stylesheet" href="https://pyscript.net/releases/2024.3.2/core.css">
2424
<!-- This script tag bootstraps PyScript -->
25-
<script type="module" src="https://pyscript.net/releases/2024.3.1/core.js"></script>
25+
<script type="module" src="https://pyscript.net/releases/2024.3.2/core.js"></script>
2626
</head>
2727
<body>
2828
<!-- your code goes here... -->

docs/user-guide/plugins.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Here's an example of how a PyScript plugin looks like:
1414

1515
```js
1616
// import the hooks from PyScript first...
17-
import { hooks } from "https://pyscript.net/releases/2024.3.1/core.js";
17+
import { hooks } from "https://pyscript.net/releases/2024.3.2/core.js";
1818

1919
// Use the `main` attribute on hooks do define plugins that run on the main thread
2020
hooks.main.onReady.add((wrap, element) => {

mkdocs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ nav:
7171
- First steps: user-guide/first-steps.md
7272
- Architecture: user-guide/architecture.md
7373
- Configuration: user-guide/configuration.md
74-
- The DOM: user-guide/dom.md
74+
- The DOM &amp; JavaScript: user-guide/dom.md
7575
- Workers: user-guide/workers.md
7676
- Builtin helpers: user-guide/builtins.md
7777
- Python terminal: user-guide/terminal.md

version.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"version": "2024.3.1"
2+
"version": "2024.3.2"
33
}

0 commit comments

Comments
 (0)