Skip to content

Commit f1cdf63

Browse files
committed
Added first example into docs/examples
1 parent 48f6601 commit f1cdf63

14 files changed

Lines changed: 2901 additions & 1 deletion

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ node_modules/
44
cjs/*
55
!cjs/package.json
66
core.js
7+
!docs/core.js
78
pyscript.js
89
!esm/custom/pyscript.js
910
esm/worker/xworker.js

.npmignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ node_modules/
1111
pyscript/
1212
rollup/
1313
test/
14+
docs/
1415
index.html
1516
node.importmap
1617
sw.js

docs/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* [How Events Work](#how-events-work) - how `<button py-click="...">` works
1111
* [XWorker](#xworker) - how `XWorker` class and its `xworker` reference work
1212
* [Custom Scripts](#custom-scripts) - how *custom types* can be defined and used to enrich any core feature
13+
* [Examples](#examples) - some *polyscript* based live example
1314

1415

1516
## Terminology
@@ -486,3 +487,8 @@ wrap.io.stderr = (message) => {
486487
console.error("🌑", wrap.type, message);
487488
};
488489
```
490+
491+
## Examples
492+
493+
* [multi-pompom](./examples/multi-pompom/) - draw 4 pompom via turtle out of 4 different workers
494+
* [non-blocking input](./examples/worker-input/) - ask a question from a worker and log results in a sync-like, yet non-blocking, style

docs/coi.js

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*! coi-serviceworker v0.1.6 - Guido Zuidhof, licensed under MIT */
2+
let coepCredentialless = false;
3+
4+
if (typeof window === 'undefined') {
5+
self.addEventListener("install", () => self.skipWaiting());
6+
self.addEventListener("activate", (event) => event.waitUntil(self.clients.claim()));
7+
8+
self.addEventListener("message", (ev) => {
9+
if (!ev.data) {
10+
return;
11+
} else if (ev.data.type === "deregister") {
12+
self.registration
13+
.unregister()
14+
.then(() => {
15+
return self.clients.matchAll();
16+
})
17+
.then(clients => {
18+
clients.forEach((client) => client.navigate(client.url));
19+
});
20+
} else if (ev.data.type === "coepCredentialless") {
21+
coepCredentialless = ev.data.value;
22+
}
23+
});
24+
25+
self.addEventListener("fetch", function (event) {
26+
const r = event.request;
27+
if (r.cache === "only-if-cached" && r.mode !== "same-origin") {
28+
return;
29+
}
30+
31+
const request = (coepCredentialless && r.mode === "no-cors")
32+
? new Request(r, {
33+
credentials: "omit",
34+
})
35+
: r;
36+
event.respondWith(
37+
fetch(request)
38+
.then((response) => {
39+
if (response.status === 0) {
40+
return response;
41+
}
42+
43+
const newHeaders = new Headers(response.headers);
44+
newHeaders.set("Cross-Origin-Embedder-Policy",
45+
coepCredentialless ? "credentialless" : "require-corp"
46+
);
47+
48+
if (!coepCredentialless) {
49+
newHeaders.set("Cross-Origin-Resource-Policy", "cross-origin");
50+
}
51+
52+
newHeaders.set("Cross-Origin-Opener-Policy", "same-origin");
53+
54+
return new Response(response.body, {
55+
status: response.status,
56+
statusText: response.statusText,
57+
headers: newHeaders,
58+
});
59+
})
60+
.catch((e) => console.error(e))
61+
);
62+
});
63+
64+
} else {
65+
(() => {
66+
// You can customize the behavior of this script through a global `coi` variable.
67+
const coi = {
68+
shouldRegister: () => true,
69+
shouldDeregister: () => false,
70+
coepCredentialless: () => !(window.chrome || window.netscape),
71+
doReload: () => window.location.reload(),
72+
quiet: true,
73+
...window.coi
74+
};
75+
76+
const n = navigator;
77+
78+
if (n.serviceWorker && n.serviceWorker.controller) {
79+
n.serviceWorker.controller.postMessage({
80+
type: "coepCredentialless",
81+
value: coi.coepCredentialless(),
82+
});
83+
84+
if (coi.shouldDeregister()) {
85+
n.serviceWorker.controller.postMessage({ type: "deregister" });
86+
}
87+
}
88+
89+
// If we're already coi: do nothing. Perhaps it's due to this script doing its job, or COOP/COEP are
90+
// already set from the origin server. Also if the browser has no notion of crossOriginIsolated, just give up here.
91+
if (window.crossOriginIsolated !== false || !coi.shouldRegister()) return;
92+
93+
if (!window.isSecureContext) {
94+
!coi.quiet && console.log("COOP/COEP Service Worker not registered, a secure context is required.");
95+
return;
96+
}
97+
98+
// In some environments (e.g. Chrome incognito mode) this won't be available
99+
if (n.serviceWorker) {
100+
n.serviceWorker.register(window.document.currentScript.src).then(
101+
(registration) => {
102+
!coi.quiet && console.log("COOP/COEP Service Worker registered", registration.scope);
103+
104+
registration.addEventListener("updatefound", () => {
105+
!coi.quiet && console.log("Reloading page to make use of updated COOP/COEP Service Worker.");
106+
coi.doReload();
107+
});
108+
109+
// If the registration is active, but it's not controlling the page
110+
if (registration.active && !n.serviceWorker.controller) {
111+
!coi.quiet && console.log("Reloading page to make use of COOP/COEP Service Worker.");
112+
coi.doReload();
113+
}
114+
},
115+
(err) => {
116+
!coi.quiet && console.error("COOP/COEP Service Worker failed to register:", err);
117+
}
118+
);
119+
}
120+
})();
121+
}

docs/core.js

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>Polyscript Multiple Turtle Pompom</title>
5+
<meta charset="UTF-8">
6+
<meta name="viewport" content="width=device-width,initial-scale=1">
7+
<!-- allows GitHub pages to serve files with the right headers -->
8+
<script src="../../coi.js"></script>
9+
<!-- polyscript entry-point file -->
10+
<script type="module" src="../../core.js"></script>
11+
</head>
12+
<body>
13+
<script type="micropython" src="./main.py"></script>
14+
</body>
15+
</html>

docs/examples/multi-pompom/main.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from polyscript import XWorker
2+
3+
# generates 4 pompom via 4 different micropython workers
4+
for i in range(4):
5+
sync = XWorker("pompom.py", config="./turtle.toml")
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# a simple turtle based pompom
2+
import turtle
3+
import random
4+
5+
turtle.set_defaults(canvwidth=300, canvheight=240)
6+
7+
colours = [
8+
"red",
9+
"green",
10+
"blue",
11+
"yellow",
12+
"orange",
13+
"brown",
14+
"gold",
15+
"purple",
16+
"black",
17+
]
18+
19+
turtle.speed(8)
20+
turtle.pensize(12)
21+
22+
for i in range(100):
23+
turtle.penup()
24+
turtle.setpos(0, 0)
25+
turtle.left(random.randint(1, 360))
26+
turtle.pendown()
27+
turtle.color(random.choice(colours))
28+
turtle.forward(random.randint(20, 90))
29+
30+
turtle.Screen().show_scene()
31+
result = turtle.svg()
32+
33+
# create the element and append it on the body
34+
from polyscript import xworker
35+
36+
document = xworker.window.document
37+
38+
container = document.createElement("span")
39+
container.innerHTML = result
40+
document.body.appendChild(container)

docs/examples/multi-pompom/svg.py

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
"""
2+
A rewrite of Brython's SVG module, to remove JavaScript / document related
3+
interactions (so this can be used within a web worker, where document is not
4+
conveniently available).
5+
6+
Author: Nicholas H.Tollervey (ntollervey@anaconda.com)
7+
Based on original work by: Romain Casati
8+
9+
License: GPL v3 or higher.
10+
"""
11+
12+
13+
class Node:
14+
"""
15+
Represents a node in the DOM.
16+
"""
17+
18+
def __init__(self, **kwargs):
19+
self._node = kwargs
20+
self.parent = kwargs.get("parent")
21+
22+
@property
23+
def outerHTML(self):
24+
"""
25+
Get a string representation of the element's outer HTML.
26+
"""
27+
return NotImplemented
28+
29+
30+
class ElementNode(Node):
31+
"""
32+
An element defined by a tag, may have attributes and children.
33+
"""
34+
35+
def __init__(self, **kwargs):
36+
super().__init__(**kwargs)
37+
self.tagName = kwargs["tagName"]
38+
self.attributes = kwargs.get("attributes", {})
39+
self.value = kwargs.get("value")
40+
self.childNodes = []
41+
42+
def appendChild(self, child):
43+
"""
44+
Add a child node to the children of this node. Using DOM API naming
45+
conventions.
46+
"""
47+
child.parent = self
48+
self.childNodes.append(child)
49+
50+
def setAttribute(self, key, value):
51+
"""
52+
Sets an attribute on the node.
53+
"""
54+
self.attributes[key] = value
55+
56+
@property
57+
def outerHTML(self):
58+
"""
59+
Get a string representation of the element's outer HTML. Using DOM API
60+
naming conventions.
61+
"""
62+
result = "<" + self.tagName
63+
for attr, val in self.attributes.items():
64+
result += " " + attr + '="' + str(val) + '"'
65+
result += ">"
66+
result += self.innerHTML
67+
result += "</" + self.tagName + ">"
68+
return result
69+
70+
@property
71+
def innerHTML(self):
72+
"""
73+
Get a string representation of the element's inner HTML. Using DOM API
74+
naming conventions.
75+
"""
76+
result = ""
77+
for child in self.childNodes:
78+
result += child.outerHTML
79+
return result
80+
81+
82+
class TextNode(Node):
83+
"""
84+
Textual content inside an ElementNode.
85+
"""
86+
87+
def __init__(self, **kwargs):
88+
super().__init__(**kwargs)
89+
self.nodeValue = kwargs.get("nodeValue")
90+
91+
@property
92+
def outerHTML(self):
93+
"""
94+
Get a string representation of the element's outer HTML.
95+
"""
96+
return self.nodeValue
97+
98+
99+
_svg_ns = "http://www.w3.org/2000/svg"
100+
_xlink_ns = "http://www.w3.org/1999/xlink"
101+
102+
103+
def _tag_func(tag):
104+
def func(*args, **kwargs):
105+
node = ElementNode(tagName=tag)
106+
# this is mandatory to display svg properly
107+
if tag == "svg":
108+
node.setAttribute("xmlns", _svg_ns)
109+
for arg in args:
110+
if isinstance(arg, (str, int, float)):
111+
arg = TextNode(nodeValue=str(arg))
112+
node.appendChild(arg)
113+
for key, value in kwargs.items():
114+
key = key.lower()
115+
if key[0:2] == "on":
116+
# Ignore event handlers within the SVG. This shouldn't happen.
117+
pass
118+
elif key == "style":
119+
node.setAttribute(
120+
"style", ";".join(f"{k}: {v}" for k, v in value.items())
121+
)
122+
elif value is not False:
123+
node.setAttribute(key.replace("_", "-"), str(value))
124+
return node
125+
126+
return func
127+
128+
129+
a = _tag_func("a")
130+
altGlyph = _tag_func("altGlyph")
131+
altGlyphDef = _tag_func("altGlyphDef")
132+
altGlyphItem = _tag_func("altGlyphItem")
133+
animate = _tag_func("animate")
134+
animateColor = _tag_func("animateColor")
135+
animateMotion = _tag_func("animateMotion")
136+
animateTransform = _tag_func("animateTransform")
137+
circle = _tag_func("circle")
138+
clipPath = _tag_func("clipPath")
139+
color_profile = _tag_func("color_profile")
140+
cursor = _tag_func("cursor")
141+
defs = _tag_func("defs")
142+
desc = _tag_func("desc")
143+
ellipse = _tag_func("ellipse")
144+
feBlend = _tag_func("feBlend")
145+
foreignObject = _tag_func("foreignObject")
146+
g = _tag_func("g")
147+
image = _tag_func("image")
148+
line = _tag_func("line")
149+
linearGradient = _tag_func("linearGradient")
150+
marker = _tag_func("marker")
151+
mask = _tag_func("mask")
152+
path = _tag_func("path")
153+
pattern = _tag_func("pattern")
154+
polygon = _tag_func("polygon")
155+
polyline = _tag_func("polyline")
156+
radialGradient = _tag_func("radialGradient")
157+
rect = _tag_func("rect")
158+
set = _tag_func("set")
159+
stop = _tag_func("stop")
160+
svg = _tag_func("svg")
161+
text = _tag_func("text")
162+
tref = _tag_func("tref")
163+
tspan = _tag_func("tspan")
164+
use = _tag_func("use")

0 commit comments

Comments
 (0)