diff --git a/docs/beginning-pyscript.md b/docs/beginning-pyscript.md
index 2cde017..cc5d933 100644
--- a/docs/beginning-pyscript.md
+++ b/docs/beginning-pyscript.md
@@ -106,8 +106,8 @@ module in the document's `
` tag:
🦜 Polyglot - Piratical PyScript
-
-
+
+
@@ -157,8 +157,8 @@ In the end, our HTML should look like this:
🦜 Polyglot - Piratical PyScript
-
-
+
+
Polyglot 🦜 💬 🇬🇧 ➡️ 🏴☠️
diff --git a/docs/user-guide/builtins.md b/docs/user-guide/builtins.md
index 05c30ee..ee6f823 100644
--- a/docs/user-guide/builtins.md
+++ b/docs/user-guide/builtins.md
@@ -193,6 +193,21 @@ response = await fetch("https://example.com", method="POST", body="HELLO").text(
bug). However, you could use a pass-through proxy service to get around
this limitation (i.e. the proxy service makes the call on your behalf).
+### `pyscript.ffi.to_js`
+
+A utility function to convert Python references into their JavaScript
+equivalents. For example, a Python dictionary is converted into a JavaScript
+object literal (rather than a JavaScript `Map`), unless a `dict_converter`
+is explicitly specified and the runtime is Pyodide.
+
+### `pyscript.ffi.create_proxy`
+
+A utility function explicitly for when a callback function is added via an
+event listener. It ensures the function still exists beyond the assignment of
+the function to an event. Should you not `create_proxy` around the callback
+function, it will be immediately garbage collected after being bound to the
+event.
+
## Main-thread only features
### `pyscript.PyWorker`
diff --git a/docs/user-guide/configuration.md b/docs/user-guide/configuration.md
index ff5614b..5abfcb7 100644
--- a/docs/user-guide/configuration.md
+++ b/docs/user-guide/configuration.md
@@ -160,6 +160,10 @@ examples could be equivalently re-written as:
... etc ...
```
+If the source part of the configuration is either a `.zip` or `.tar.gz` file
+and its destination is a folder path followed by a star (e.g. `/*` or
+`./dest/*`), then PyScript will extract the referenced archive automatically
+into the target directory in the browser's built in file system.
!!! warning
@@ -312,12 +316,9 @@ plugins = ["custom_plugin", "!error"]
### JavaScript modules
-It's easy to import and use JavaScript modules in your Python code.
-
-!!! warning
-
- This feature currently only works with Pyodide. MicroPython support will
- come in a future release.
+It's easy to import and use JavaScript modules in your Python code. This
+section of the docs examines the configuration needed to make this work. How
+to make use of JavaScript is dealt with [elsewhere](../dom/#working-with-javascript).
To do so, requires telling PyScript about the JavaScript modules you want to
use. This is the purpose of the `js_modules` related configuration fields.
diff --git a/docs/user-guide/dom.md b/docs/user-guide/dom.md
index edd8233..ae58a08 100644
--- a/docs/user-guide/dom.md
+++ b/docs/user-guide/dom.md
@@ -68,6 +68,10 @@ equivalent values: `["hello", 1, 2, 3]`.
instantiation very differently. By explicitly calling the JavaScript
class's `new` method PyScript both signals and honours this difference.
+Should you require lower level API access to FFI features, you can find such
+builtin functions under the `pyscript.ffi` namespace in both Pyodide and
+MicroPython. The available functions are described in our section on
+[builtin helpers](../builtins).
## PyDom
@@ -253,3 +257,237 @@ paragraphs.style['background-color'] = 'lightyellow'
a collection by setting the proper CSS rules, using `style` with the same API as a dictionary.
* `html`: allows to change the `html` attribute on all the elements of a collection.
* `value`: allows to change the `value` attribute on all the elements of a collection.
+
+## Working with JavaScript
+
+There are three ways in which JavaScript can get into a web page.
+
+1. As a global reference attached to the `window` object in the web page
+ because the code was referenced as the source of a `script` tag in your HTML
+ (the very old school way to do this).
+2. Using the [Universal Module Definition](https://github.com/umdjs/umd) (UMD)
+ - an out-of-date and non-standard way to create JavaScript modules.
+3. As a standard
+ [JavaScript Module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules)
+ which is the modern, standards compliant way to define and use a JavaScript
+ module. If possible, this is the way you should do things.
+
+Sadly, this being the messy world of the web, methods 1 and 2 are still quite
+common, and so you need to know about them so you're able to discern and work
+around them. There's nothing WE can do about this situation, but we can
+suggest "best practice" ways to work around each situation.
+
+Remember, as mentioned
+[elsewhere in our documentation](../configuration/#javascript-modules),
+the standard way to get JavaScript modules into your PyScript Python context is
+to link a _source_ standard JavaScript module to a _destination_ name:
+
+```toml title="Reference a JavaScript module in the configuration."
+[js_modules.main]
+"https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet-src.esm.js" = "leaflet"
+```
+
+Then, reference the module via the destination name in your Python code, by
+importing it from the `pyscript.js_modules` namespace:
+
+```python title="Import the JavaScript module into Python"
+from pyscript.js_modules import leaflet as L
+
+map = L.map("map")
+
+# etc....
+```
+
+We'll deal with each of the potential JavaScript related situations in turn:
+
+### JavaScript as a global reference
+
+In this situation, you have some JavaScript code that just globally defines
+"stuff" in the context of your web page via a `script` tag. Your HTML will
+contain something like this:
+
+```html title="JavaScript as a global reference"
+
+
+
+
+
+
+```
+
+When you find yourself in this situation, simply use the `window` object in
+your Python code (found in the `pyscript` namespace) to interact with the
+resulting JavaScript objects:
+
+```python title="Python interaction with the JavaScript global reference"
+from pyscript import window, document
+
+
+# The window object is the global context of your web page.
+html = window.html
+
+# Just use the object "as usual"...
+# e.g. show escaped HTML in the body: <>
+document.body.append(html.escape("<>"))
+```
+
+You can find an example of this technique here:
+
+[https://pyscript.com/@agiammarchi/floral-glade/v1](https://pyscript.com/@agiammarchi/floral-glade/v1)
+
+### JavaScript as a non-standard UMD module
+
+Sadly, these sorts of non-standard JavaScript modules are still quite
+prevalent. But the good news is there are strategies you can use to help you
+get them to work properly.
+
+The non-standard UMD approach tries to check for `export` and `module` fields
+in the JavaScript module and, if it doesn’t find them, falls back to treating
+the module in the same way as a global reference described above.
+
+If you find you have a UMD JavaScript module, there are services online to
+automagically convert it to the modern and standards compliant way to d
+o JavaScript modules. A common (and usually reliable) service is provided by
+[https://esm.run/your-module-name](https://esm.run/your-module-name), a
+service that provides an out of the box way to consume the module in the
+correct and standard manner:
+
+```html title="Use esm.run to automatically convert a non-standard UMD module"
+
+
+```
+
+If a similar test works for the module you want to use, use the esm.run CDN
+service within the `py` or `mpy` configuration file as explained at the start
+of this section on JavaScript (i.e. you'll use it via the `pyscript.js_modules`
+namespace).
+
+If this doesn't work, assume the module is not updated nor migrated to a state
+that can be automatically translated by services like esm.run. You could try an
+alternative (more modern) JavaScript module to achieve you ends or (if it
+really must be this module), you can wrap it in a new JavaScript module that
+conforms to the modern standards.
+
+The following four files demonstrate this approach:
+
+```html title="index.html - still grab the script so it appears as a global reference."
+
+...
+
+
+...
+```
+
+```js title="wrapper.js - this grabs the JavaScript functionality from the global context and wraps it (exports it) in the modern standards compliant manner."
+// get all utilities needed from the global.
+const { escape, unescape } = globalThis.html;
+
+// export utilities like a standards compliant module would do.
+export { escape, unescape };
+```
+
+```toml title="pyscript.toml - configure your JS modules as before, but use your wrapper instead of the original module."
+[js_modules.main]
+# will simulate a standard JS module
+"./wrapper.js" = "html_escaper"
+```
+
+```python title="main.py - just import the module as usual and make use of it."
+from pyscript import document
+
+# import the module either via
+from pyscript.js_modules import html_escaper
+# or via
+from pyscript.js_modules.html_escaper import escape, unescape
+
+# show on body: <>
+document.body.append(html.escape("<>"))
+```
+
+You can see this approach in action here:
+
+[https://pyscript.com/@agiammarchi/floral-glade/v2](https://pyscript.com/@agiammarchi/floral-glade/v2)
+
+### A standard JavaScript module
+
+This is both the easiest and best way to import any standard JS module into
+Python.
+
+You don't need to reference the script in your HTML, just define how the source
+JavaScript module maps into the `pyscript.js_modules` namespace in your
+configuration file, as explained above.
+
+That's it!
+
+Here is an example project that uses this approach:
+
+[https://pyscript.com/@agiammarchi/floral-glade/v3](https://pyscript.com/@agiammarchi/floral-glade/v3)
+
+
+### My own JavaScript code
+
+If you have your own JavaScript work, just remember to write it as a standard
+JavaScript module. Put simply, ensure you `export` the things you need to. For
+instance, in the following fragment of JavaScript, the two functions are
+exported from the module:
+
+```js title="code.js - containing two functions exported as capabilities of the module."
+/*
+Some simple JavaScript functions for example purposes.
+*/
+
+export function hello(name) {
+ return "Hello " + name;
+}
+
+export function fibonacci(n) {
+ if (n == 1) return 0;
+ if (n == 2) return 1;
+ return fibonacci(n - 1) + fibonacci(n - 2);
+}
+```
+
+Next, just reference this module in the usual way in your TOML or JSON
+configuration file:
+
+```TOML title="pyscript.toml - references the code.js module so it will appear as the code module in the pyscript.js_modules namespace."
+[js_modules.main]
+"code.js" = "code"
+```
+
+In your HTML, reference your Python script with this configuration file:
+
+```html title="Reference the expected configuration file."
+
+```
+
+Finally, just use your JavaScript module’s exported functions inside PyScript:
+
+```python title="Just call your bespoke JavaScript code from Python."
+from pyscript.js_modules import code
+
+
+# Just use the JS code from Python "as usual".
+greeting = code.hello("Chris")
+print(greeting)
+result = code.fibonacci(12)
+print(result)
+```
+
+You can see this in action in the following example project:
+
+[https://pyscript.com/@ntoll/howto-javascript/latest](https://pyscript.com/@ntoll/howto-javascript/latest)
diff --git a/docs/user-guide/first-steps.md b/docs/user-guide/first-steps.md
index 6256d1e..0d1cb86 100644
--- a/docs/user-guide/first-steps.md
+++ b/docs/user-guide/first-steps.md
@@ -20,9 +20,9 @@ CSS:
-
+
-
+
diff --git a/docs/user-guide/plugins.md b/docs/user-guide/plugins.md
index 5921e6c..3575683 100644
--- a/docs/user-guide/plugins.md
+++ b/docs/user-guide/plugins.md
@@ -14,7 +14,7 @@ Here's an example of how a PyScript plugin looks like:
```js
// import the hooks from PyScript first...
-import { hooks } from "https://pyscript.net/releases/2024.3.1/core.js";
+import { hooks } from "https://pyscript.net/releases/2024.3.2/core.js";
// Use the `main` attribute on hooks do define plugins that run on the main thread
hooks.main.onReady.add((wrap, element) => {
diff --git a/mkdocs.yml b/mkdocs.yml
index a3d5827..0e190a1 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -71,7 +71,7 @@ nav:
- First steps: user-guide/first-steps.md
- Architecture: user-guide/architecture.md
- Configuration: user-guide/configuration.md
- - The DOM: user-guide/dom.md
+ - The DOM & JavaScript: user-guide/dom.md
- Workers: user-guide/workers.md
- Builtin helpers: user-guide/builtins.md
- Python terminal: user-guide/terminal.md
diff --git a/version.json b/version.json
index 0ca80dc..30bce84 100644
--- a/version.json
+++ b/version.json
@@ -1,3 +1,3 @@
{
- "version": "2024.3.1"
+ "version": "2024.3.2"
}