Skip to content

Commit f49c5b8

Browse files
committed
WiP - needs checking with pyscript.web status before merging.
1 parent 109138d commit f49c5b8

File tree

8 files changed

+540
-421
lines changed

8 files changed

+540
-421
lines changed

docs/user-guide/builtins.md renamed to docs/api.md

Lines changed: 405 additions & 266 deletions
Large diffs are not rendered by default.

docs/beginning-pyscript.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ application's output.
147147
There's something strange about the `<button>` tag: it has a `py-click`
148148
attribute with the value `translate_english`. This is, in fact, the name of a
149149
Python function we'll run whenever the button is clicked. Such `py-*` style
150-
attributes are [built into PyScript](user-guide/builtins.md#html-attributes).
150+
attributes are [built into PyScript](api.md#html-attributes).
151151

152152
We put all this together in the `script` tag at the end of the `<body>`. This
153153
tells the browser we're using PyScript (`type="py"`), and where PyScript

docs/faq.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ hence the error message.
200200
If you encounter this problem you have two possible solutions:
201201

202202
1. Manually wrap such functions with a call to
203-
[`pyscript.ffi.create_proxy`](../builtins/#pyscriptfficreate_proxy).
203+
[`pyscript.ffi.create_proxy`](../../api/#pyscriptfficreate_proxy).
204204
2. Set the
205205
[`experimental_create_proxy = "auto"`](../configuration/#experimental_create_proxy)
206206
flag in your application's settings. This flag intercepts Python objects
@@ -922,7 +922,7 @@ def download_file(path, mime_type):
922922
### create_proxy
923923

924924
The `create_proxy` function is described in great detail
925-
[on the FFI page](../ffi/), but it's also useful to explain _when_
925+
[on the FFI page](../user-guide/ffi/), but it's also useful to explain _when_
926926
`create_proxy` is needed and the subtle differences between Pyodide and
927927
MicroPython.
928928

docs/user-guide/architecture.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ Here's how PyScript unfolds through time:
181181
[plugins](configuration.md/#plugins), [packages](configuration.md/#packages), [files](configuration.md/#files) or [JavaScript modules](configuration.md/#javascript-modules)
182182
that need to be loaded.
183183
5. Make available various
184-
[builtin helper objects and functions](builtins.md) to the
184+
[builtin helper objects and functions](../../api) to the
185185
interpreter's environment (accessed via the `pyscript` module).
186186
6. Only then use the interpreter in the correctly configured environment to
187187
evaluate the detected Python code.

docs/user-guide/dom.md

Lines changed: 124 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -73,204 +73,184 @@ equivalent values: `["hello", 1, 2, 3]`.
7373

7474
Should you require lower level API access to FFI features, you can find such
7575
builtin functions under the `pyscript.ffi` namespace in both Pyodide and
76-
MicroPython. The available functions are described in our section on
77-
[builtin helpers](../builtins).
76+
MicroPython. The available functions are described in our section on the
77+
[builtin API](../../api).
7878

7979
Advanced users may wish to explore the
8080
[technical details of the FFI](../ffi).
8181

82-
## PyDom
83-
84-
The Standard Web APIs are massive and not always very user-friendly. `PyDom` is
85-
a Python module that exposes the power of the web with an easy and idiomatic
86-
Pythonic interface on top.
87-
88-
While the [FFI](#ffi) interface described above focuses on giving full access
89-
to the entire Standard Web APIs, `pydom` focuses on providing a small,
90-
intuitive and yet powerful API that prioritises common use cases fist. For this
91-
reason, its first layer is simple (but limited to the most common use cases),
92-
but `pydom` also provides a secondary layer to directly use full FFI interface
93-
of a specific element.
94-
95-
PyDom does not aim to replace the regular web (Javascript) API nor to be as
96-
wide and offer feature parity. On the contrary, it is intentionally small and
97-
focused on the most popular use cases while still providing (backdoor) access
98-
to the full JavaScript API.
99-
100-
`Pydom` draws inspiration from popular Python APIs/Libraries known to be
101-
friendly and easy to learn, and other successful projects related the web as
102-
well (for instance, `JQuery` was a source of inspiration).
82+
## `pyscript.web`
10383

10484
!!! warning
10585

106-
PyDom is currently a work in progress.
86+
The `pyscript.web` module is currently a work in progress.
10787

10888
We welcome feedback and suggestions.
10989

90+
The `pyscript.web` module is an idiomatically Pythonic API for interacting with
91+
the DOM. It wraps the FFI in a way that is more familiar to Python developers
92+
and works natively with the Python language. Technical documentation for this
93+
module can be found in [the API](../../api/#pyscriptweb) section.
11094

111-
### Core Concepts
95+
There are three core concepts to remember:
11296

113-
`Pydom` builds on topic of very few and simple core concepts:
114-
115-
* __`Element`:__ any component that is part of a web page. This is a rough
116-
abstraction of an
117-
[HTMLElement](https://developer.mozilla.org/en-US/docs/Glossary/Element).
118-
In general, `pydom` elements always map to an underlying `HTML` `Element` in
119-
a web page
120-
* __`ElementCollection`:__ a collection of one or more `Elements`. It is a
121-
rough abstraction of an
122-
[HTMLCollection](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection).
123-
* __Querying:__ a method to query elements on a page based on a
124-
[selector](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_selectors).
125-
Pydom supports standard HTML DOM query selectors to
126-
[locate DOM elements](https://developer.mozilla.org/en-US/docs/Web/API/Document_object_model/Locating_DOM_elements_using_selectors)
127-
as other native `JavaScript` methods like `querySelector` or
97+
* Find elements on the page via
98+
[CSS selectors](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_selectors).
99+
The `find` API uses exactly the [same queries](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Locating_DOM_elements_using_selectors)
100+
as those used by native browser methods like `qurerySelector` or
128101
`querySelectorAll`.
102+
* Use classes in the `pyscript.web.elements` namespace to create and organise
103+
new elements on the web page.
104+
* Collections of elements allow you to access and change attributes en-mass.
105+
Such collections are returned from `find` queries and are also used for the
106+
[children](https://developer.mozilla.org/en-US/docs/Web/API/Element/children)
107+
of an element.
108+
109+
You have several options for accessing the content of the page (i.e. the DOM),
110+
and these can be found in the `pyscript.web.dom` object. The `head` and `body`
111+
attributes reference the page's head and body. Furthermore, the `find` method
112+
can be used to return collections of elements matching your CSS query. Finally,
113+
all elements have a `find` method that searches within their children for
114+
elements matching your CSS query.
129115

130-
Let's look into each of these aspects in more in detail.
131-
132-
### Element
116+
```python
117+
from pyscript.web import dom
133118

134-
A PyDom `Element` is simply an abstraction of a tranditional `Element` in a web
135-
page. Every PyDom `Element` maps to an underlying JavaScript `Element` in a
136-
web page. These two elements are always in sync and any change of state in one
137-
is reflected in the other.
138119

139-
#### Creating a new element
120+
# Print all the child elements of the document's head.
121+
print(dom.head.children)
122+
# Find all the paragraphs in the DOM.
123+
paragraphs = dom.find("p")
124+
```
140125

141-
New elements are created using the `pydom.create` method and passing the type
142-
of element being created. Here's an example of what it looks like:
126+
The object returned from a query, or used as a reference to an element's
127+
children is iterable:
143128

144129
```python
145-
from pyweb import pydom
130+
from pyscript.web import dom
146131

147-
# Creating an element directly from pydom creates an unbounded element.
148-
new_div = pydom.create("div")
149132

150-
# Creating an element from another element automatically creates that element
151-
# as a child of the original element
152-
new_p = new_div.create(
153-
"p",
154-
classes=["code-description"],
155-
html="Ciao PyScripters!"
156-
)
133+
# Get all the paragraphs in the DOM.
134+
paragraphs = dom.find("p")
157135

158-
# elements can be appended to any other element on the page
159-
pydom['#element-creation-example'][0].append(new_div)
136+
# Print the inner html of each paragraph.
137+
for p in paragraphs:
138+
print(p.html)
160139
```
161140

162-
#### Setting an element's content
163-
164-
The `Element` interface offers two ways to set an element's content: the `html`
165-
and the `content` attributes:
166-
167-
* `html`: directly sets the `innerHTML` field of the underlying element without
168-
attemnpting any conversion.
169-
* `content`: sets the `innerHTML` field via the PyScript `display` function.
170-
This takes care of properly rendering the object being passed based on the
171-
object mimetype. So, for instance, if the objects is an image, it'll be
172-
properly rendered within the element
141+
Alternatively, it is also indexable / sliceable:
173142

174-
In general, we suggest using `content` directly as it'll take care of most use
175-
cases without requiring any extra work from the user.
143+
```python
144+
from pyscript.web import dom
176145

177-
#### Changing an element's style
178146

179-
Elements have a `style` attribute to change the element style rules. The
180-
`style` attribute is a dictionary and, to set a style rule for the element,
181-
simply set the correct key on the `.style` attribute. For instance, the
182-
following code changes the background color (of the element created in the
183-
example above):
147+
# Get an ElementCollection of all the paragraphs in the DOM
148+
paragraphs = dom.find("p")
184149

185-
```python
186-
new_p.style["background-color"] = "yellow"
150+
# Only the final two paragraphs.
151+
for p in paragraphs[-2:]:
152+
print(p.html)
187153
```
188154

189-
To remove a style key, simply use the `pop` method as you'd to to remove
190-
a key from a dictionary:
155+
It also makes available the following read and writable attributes related to
156+
all contained elements:
191157

192-
```python
193-
new_p.style.pop("background-color")
194-
```
158+
* `style` - a dictionary like object for interacting with CSS style rules.
159+
* `html` - the `innerHTML` of each element.
160+
* `value` - the `value` attribute associated with each element.
161+
162+
For example, to continue the example above, `paragraphs.html` will return a
163+
list of all the values of the `html` attribute on each contained element.
164+
Alternatively, set an attribute for all elements contained in the
165+
collection like this: `paragraphs.style["background-color"] = "blue"`.
195166

196-
In addition to the dictionary interface to explicitly set CSS rules, the
197-
`style` attribute also offers a convenient `visible` property that can be use
198-
show/hide an element.
167+
It's possible to create new elements to add to the DOM:
199168

200169
```python
201-
new_p.style.visible = False
170+
from pyscript.web import dom
171+
from pyscript.web.elements import *
172+
173+
174+
dom.body.append(
175+
div(
176+
div("Hello!", classes="a-css-class", id="hello"),
177+
select(
178+
option("apple", value=1),
179+
option("pear", value=2),
180+
option("orange", value=3),
181+
),
182+
div(
183+
button(span("Hello! "), span("World!"), id="my-button"),
184+
br(),
185+
button("Click me!"),
186+
classes=["css-class1", "css-class2"],
187+
style={"background-color": "red"}
188+
),
189+
div(
190+
children=[
191+
button(
192+
children=[
193+
span("Hello! "),
194+
span("Again!")
195+
],
196+
id="another-button"
197+
),
198+
br(),
199+
button("b"),
200+
],
201+
classes=["css-class1", "css-class2"]
202+
)
203+
)
204+
)
202205
```
203206

204-
#### Other useful aspects of the Element API
207+
This example demonstrates a declaritive way to add elements to the body of the
208+
DOM. Notice how the first (unnamed) arguments to an element are its child. The
209+
named arguments (such as `id`, `classes` and `style`) refer to attributes of
210+
the underlying HTML element. If you'd rather be explicit about the children of
211+
an element, you can always pass in a list of such elements as the named
212+
`children` argument (you see this in the final `div` in the example above).
205213

206-
* `append`: a method to append a new child to the element.
207-
* `children`: list of the children of the element.
208-
* `value`: allows to set the `value` attribute of an element.
209-
* `clone`: a method that creates a clone of the element. NOTE: The cloned
210-
elements will not be attached to any other element.
211-
* `show_me`: a method to scroll the page to where the element is placed.
214+
Of course, you can achieve similar results in an imperative style of
215+
programming:
212216

213-
### Element collections
217+
```python
218+
from pyscript.web import dom
219+
from pyscript.web.elements import *
214220

215-
Element collections represent a collection of elements typically returned from
216-
a query. For instance:
217221

218-
```python
219-
paragraphs = pydom['p']
220-
```
221222

222-
In the example above, `paragraphs` is an `ElementCollection` that maps to all
223-
`p` elements in the page.
223+
my_div = div()
224+
my_div.style["background-color"] = "red"
225+
my_div.classes.append("a-css-class")
224226

225-
An `ElementCollection` can be used to iterate over a collection of elements or
226-
to pick specific elements or slices of elements in the collection. For
227-
instance:
227+
my_p = p()
228+
my_p.content = "This is a paragraph."
228229

229-
```python
230-
for element in paragraphs:
231-
display(element.html)
230+
my_div.append(my_p)
232231

233-
# let's now display only the last 2 elements
234-
for element in paragraphs[-2:]:
235-
display(element.html)
232+
# etc...
236233
```
237234

238-
#### Interacting with an ElementCollection
239-
240-
Besides allowing operations as an iterable object, `ElementCollection` objects
241-
also offer a few convenience methods to directly interact with the elements
242-
within the collection. For instance, it's possible to ask for specific
243-
attributes of the elements in the collection directly:
235+
It's also important to note that the `pyscript.when` decorator understands
236+
element references from `pyscript.web`:
244237

245238
```python
246-
display(paragraphs.html)
247-
```
239+
from pyscript import when
240+
from pyscript.web import dom
248241

249-
This displays a list with the values of the `html` attribute for all the
250-
elements in the `paragraphs` collection.
251242

252-
In the same way we can read attributes, we can also set an attribute directly
253-
in the collection. For instance, you can directly set the html content of all
254-
the elements in the collection:
243+
btn = dom.find("#my-button")
255244

256-
```python
257-
# This will change the text of all H1 elements in the page
258-
pydom['h1'].html = "That's cool :)"
259-
```
260245

261-
Or perhaps change their style:
262-
263-
```
264-
paragraphs.style['background-color'] = 'lightyellow'
246+
@when("click", btn)
247+
def my_button_click_handler(event):
248+
print("The button has been clicked!")
265249
```
266250

267-
The `ElementCollection` class currently supports the following attributes:
268-
269-
* `style`: just like in `Element`, this proxy attribute can be used to change
270-
the style of the elements in a collection by setting the proper CSS rules,
271-
using `style` with the same API as a dictionary.
272-
* `html`: changes the `html` attribute on all the elements of a collection.
273-
* `value`: changes the `value` attribute on all the elements of a collection.
251+
Should you wish direct access to the proxy object representing the underlying
252+
HTML element, each Python element has a `_dom_element` property for this
253+
purpose.
274254

275255
## Working with JavaScript
276256

docs/user-guide/first-steps.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ attributes:
8181
[web worker](workers.md) instead of the "main thread" that looks after the user
8282
interface.
8383
* `target` - The id or selector of the element where calls to
84-
[`display()`](builtins.md/#pyscriptdisplay) should write their values.
84+
[`display()`](../../api/#pyscriptdisplay) should write their values.
8585
* `terminal` - A traditional [terminal](terminal.md) is shown on the page.
8686
As with conventional Python, `print` statements output here. **If the
8787
`worker` flag is set the terminal becomes interactive** (e.g. use

0 commit comments

Comments
 (0)