Add Element to the API reference (#998)

This commit is contained in:
Fábio Rosado
2022-12-05 15:14:34 +00:00
committed by GitHub
parent c696d92f40
commit 9992096654
4 changed files with 618 additions and 5 deletions

View File

@@ -0,0 +1,309 @@
# `Element`
The `Element` API is a helpful way to create and manipulate elements in the DOM. It is a wrapper around the native DOM API, and is designed to be as intuitive as possible.
## Methods and Properties
| Property | Description |
|----------|-----------------------------------------|
| `element` | Returns the element with the given ID. |
| `id` | Returns the element's ID. |
| `value` | Returns the element's value. |
| `innerHtml` | Returns the element's inner HTML. |
| Method | Description |
|----------------------|--------------------------------------------------------------|
| `write` | Writes `value` to element and handles various mime types. `append` defaults to `False`, if set to true, it will create a child element. |
| `clear` | Clears the element's value or content. |
| `select` | Select element from `query` which uses [Document.querySelector()](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector). |
| `clone` | Clones the with `new_id` if provided and `to` element if provided. |
| `remove_class` | Removes one or more class name from the element. |
| `add_class` | Adds one or more class name to the element. |
## Element.element
| Parameter | Default | Type |
|-----------|---------|------|
| | | |
The `element` property returns the DOM element with the given ID.
```html
from pyscript import Element
my_div = Element('my-div')
print(my_div.element)
```
## Element.id
| Parameter | Default | Type |
|-----------|---------|------|
| | | |
Return the element's ID.
```html
<div id="my-div"></div>
<py-script>
from pyscript import Element
my_div = Element('my-div')
print(my_div.id) # prints 'my-div'
</py-script>
```
## Element.value
| Parameter | Default | Type |
|-----------|---------|------|
| | | |
Return the element's value.
```html
<input id="my-input" value="hello world"></input>
<py-script>
from pyscript import Element
my_input = Element('my-input')
print(my_input.value) # prints 'hello world'
</py-script>
```
## Element.innerHtml
| Parameter | Default | Type |
|-----------|---------|------|
| | | |
Return the element's inner HTML.
```html
<div id="my-innerHtml">
<b>hello world</b>
</div>
<py-script>
from pyscript import Element
my_innerHtml = Element('my-innerHtml')
print(my_innerHtml.innerHtml) # prints <b> hello world </b>
</py-script>
```
## Element.write
| Parameter | Default | Type |
|-------------|---------|-----------------------------|
| `value` | | `str` or `__mime_type__` |
| `append` | False | `bool` |
Writes `value` to element and handles various mime types. This method also contains a `append` parameter, which defaults to `False`.
Currently, these are the MIME types that are supported when rendering content using this method
| Method | Inferred MIME type |
|---------------------|------------------------|
| `__repr__` | text/plain |
| `_repr_html_` | text/html |
| `_repr_svg_` | image/svg+xml |
| `_repr_png_` | image/png* |
| `_repr_pdf_` | application/pdf |
| `_repr_jpeg_` | image/jpeg* |
| `_repr_json_` | application/json |
| `_repr_javascript_` | application/javascript*|
| `savefig` | image/png |
```html
<div id="foo"></div>
<py-script>
from pyscript import Element
el = Element("foo")
el.write("Hello!")
el.write("World!") # will replace the previous content
</py-script>
```
If we set `append` to `True`, it will create a child element using a `div`.
```html
<div id="foo"></div>
<py-script>
from pyscript import Element
el = Element("foo")
el.write("Hello!", append=True)
# This will create a child div with the id "foo-1"
el.write("World!", append=True)
</py-script>
```
## Element.clear
| Parameter | Default | Type |
|-----------|---------|------|
| | | |
Clears the element's value or content. For example, we can clear the value of an input element.
```html
<input id="foo" value="Hello!"></input>
<py-script>
from pyscript import Element
el = Element("foo")
el.clear() # Removes value from input
</py-script>
```
Or we can clear the content of a div element.
```html
<div id="foo">Hello!</div>
<py-script>
from pyscript import Element
el = Element("foo")
el.clear() # Removes Hello from div content
</py-script>
```
## Element.select
Select element from `query`, it will look into the main Element if `from_content` is `True`. This method is a wrapper of [Document.querySelector()](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector).
```html
<div id="foo">
<div id="bar"></div>
</div>
<py-script>
from pyscript import Element
el = Element("foo")
bar = el.select("#bar")
print(bar.id) # prints 'bar'
</py-script>
```
## Element.clone
| Parameter | Default | Type |
|-------------|---------|-----------|
| `new_id` | None | `str` |
| `to` | None | `Element` |
Clones the element to a new element. You can provide `new_id` to set a different id to the cloned element. You can also use a `to` element to append the cloned element to.
```html
<div id="foo">
HI!
</div>
<py-script>
from pyscript import Element
el = Element("foo")
# Creates two divs with the id "foo" and content "HI!"
el.clone()
</py-script>
```
It's always a good idea to pass a new id to the element you are cloning to avoid confusion if you need to reference the element by id again.
```html
<div id="foo">Hello!</div>
<py-script>
from pyscript import Element
el = Element("foo")
# Clones foo and its contents, but uses the id 'bar'
el.clone(new_id="bar")
</py-script>
```
You can also clone an element into another element.
```html
<div id="bond">
Bond
</div>
<div id="james">
James
</div>
<py-script>
from pyscript import Element
bond_div = Element("bond")
james_div = Element("james")
bond_div.clone(new_id="bond-2", to=james_div)
</py-script>
```
## Element.remove_class
| Parameter | Default | Type |
|-------------|---------|-----------------------|
| `classname` | None | `str` or `List[str]` |
Removes one or more class names from the element.
```html
<div id="foo" class="bar baz"></div>
<py-script>
from pyscript import Element
el = Element("foo")
el.remove_class("bar")
</py-script>
```
You can also remove multiple classes by passing a list of strings.
```html
<div id="foo" class="bar baz"></div>
<py-script>
from pyscript import Element
el = Element("foo")
el.remove_class(["bar", "baz"]) # Remove all classes from element
</py-script>
```
## Element.add_class
| Parameter | Default | Type |
|-------------|---------|-----------------------|
| `classname` | None | `str` or `List[str]` |
Adds one or more class names to the element.
```html
<style> .red { color: red; } </style>
<div id="foo">Hi!</div>
<py-script>
from pyscript import Element
el = Element("foo")
el.add_class("red")
</py-script>
```
You can also add multiple classes at once by passing a list of strings.
```html
<style> .red { color: red; } .bold { font-weight: bold; } </style>
<div id="foo">Hi!</div>
<py-script>
from pyscript import Element
el = Element("foo")
el.add_class(["red", "bold"])
</py-script>
```

View File

@@ -225,7 +225,7 @@ class Element:
@property
def innerHtml(self):
return self.element.innerHtml
return self.element.innerHTML
def write(self, value, append=False):
html, mime_type = format_mime(value)
@@ -255,6 +255,7 @@ class Element:
def select(self, query, from_content=False):
el = self.element
if from_content:
el = el.content
@@ -273,9 +274,11 @@ class Element:
if to:
to.element.appendChild(clone)
# Inject it into the DOM
self.element.after(clone)
# Inject it into the DOM
to.element.after(clone)
else:
# Inject it into the DOM
self.element.after(clone)
return Element(clone.id, clone)
@@ -287,7 +290,11 @@ class Element:
self.element.classList.remove(classname)
def add_class(self, classname):
self.element.classList.add(classname)
if isinstance(classname, list):
for cl in classname:
self.element.classList.add(cl)
else:
self.element.classList.add(classname)
def add_classes(element, class_list):

View File

@@ -0,0 +1,297 @@
from .support import PyScriptTest
class TestElement(PyScriptTest):
"""Test the Element api"""
def test_element_id(self):
"""Test the element id"""
self.pyscript_run(
"""
<div id="foo"></div>
<py-script>
from pyscript import Element
el = Element("foo")
print(el.id)
</py-script>
"""
)
assert self.console.log.lines[0] == self.PY_COMPLETE
assert self.console.log.lines[-1] == "foo"
py_terminal = self.page.wait_for_selector("py-terminal")
assert "foo" in py_terminal.inner_text()
def test_element_value(self):
"""Test the element value"""
self.pyscript_run(
"""
<input id="foo" value="bar">
<py-script>
from pyscript import Element
el = Element("foo")
print(el.value)
</py-script>
"""
)
assert self.console.log.lines[0] == self.PY_COMPLETE
assert self.console.log.lines[-1] == "bar"
py_terminal = self.page.wait_for_selector("py-terminal")
assert "bar" in py_terminal.inner_text()
def test_element_innerHtml(self):
"""Test the element innerHtml"""
self.pyscript_run(
"""
<div id="foo"><b>bar</b></div>
<py-script>
from pyscript import Element
el = Element("foo")
print(el.innerHtml)
</py-script>
"""
)
assert self.console.log.lines[0] == self.PY_COMPLETE
assert self.console.log.lines[-1] == "<b>bar</b>"
py_terminal = self.page.wait_for_selector("py-terminal")
assert "bar" in py_terminal.inner_text()
def test_element_write_no_append(self):
"""Test the element write"""
self.pyscript_run(
"""
<div id="foo"></div>
<py-script>
from pyscript import Element
el = Element("foo")
el.write("Hello!")
el.write("World!")
</py-script>
"""
)
assert self.console.log.lines[0] == self.PY_COMPLETE
div = self.page.wait_for_selector("#foo")
assert "World!" in div.inner_text()
def test_element_write_append(self):
"""Test the element write"""
self.pyscript_run(
"""
<div id="foo"></div>
<py-script>
from pyscript import Element
el = Element("foo")
el.write("Hello!")
el.write("World!", append=True)
</py-script>
"""
)
assert self.console.log.lines[0] == self.PY_COMPLETE
parent_div = self.page.wait_for_selector("#foo")
assert "Hello!" in parent_div.inner_text()
# confirm that the second write was appended
assert "Hello!<div>World!</div>" in parent_div.inner_html()
def test_element_clear_div(self):
"""Test the element clear"""
self.pyscript_run(
"""
<div id="foo">Hello!</div>
<py-script>
from pyscript import Element
el = Element("foo")
el.clear()
</py-script>
"""
)
assert self.console.log.lines[0] == self.PY_COMPLETE
div = self.page.locator("#foo")
assert div.inner_text() == ""
def test_element_clear_input(self):
"""Test the element clear"""
self.pyscript_run(
"""
<input id="foo" value="bar">
<py-script>
from pyscript import Element
el = Element("foo")
el.clear()
</py-script>
"""
)
assert self.console.log.lines[0] == self.PY_COMPLETE
input = self.page.wait_for_selector("#foo")
assert input.input_value() == ""
def test_element_select(self):
"""Test the element select"""
self.pyscript_run(
"""
<select id="foo">
<option value="bar">Bar</option>
</select>
<py-script>
from pyscript import Element
el = Element("foo")
el.select("bar", from_content=True)
</py-script>
"""
)
assert self.console.log.lines[0] == self.PY_COMPLETE
select = self.page.wait_for_selector("#foo")
assert select.inner_text() == "Bar"
def test_element_clone_no_id(self):
"""Test the element clone"""
self.pyscript_run(
"""
<div id="foo">Hello!</div>
<py-script>
from pyscript import Element
el = Element("foo")
el.clone()
</py-script>
"""
)
assert self.console.log.lines[0] == self.PY_COMPLETE
divs = self.page.locator("#foo")
assert divs.count() == 2
assert divs.first.inner_text() == "Hello!"
assert divs.last.inner_text() == "Hello!"
def test_element_clone_with_id(self):
"""Test the element clone"""
self.pyscript_run(
"""
<div id="foo">Hello!</div>
<py-script>
from pyscript import Element
el = Element("foo")
el.clone(new_id="bar")
</py-script>
"""
)
assert self.console.log.lines[0] == self.PY_COMPLETE
divs = self.page.locator("#foo")
assert divs.count() == 1
assert divs.inner_text() == "Hello!"
clone = self.page.locator("#bar")
assert clone.inner_text() == "Hello!"
def test_element_clone_to_other_element(self):
"""Test the element clone"""
self.pyscript_run(
"""
<div id="container">
<div id="bond">
Bond
</div>
<div id="james">
James
</div>
</div>
<py-script>
from pyscript import Element
bond_div = Element("bond")
james_div = Element("james")
bond_div.clone(new_id="bond-2", to=james_div)
</py-script>
"""
)
assert self.console.log.lines[0] == self.PY_COMPLETE
bond_divs = self.page.locator("#bond")
james_divs = self.page.locator("#james")
bond_2_divs = self.page.locator("#bond-2")
assert bond_divs.count() == 1
assert james_divs.count() == 1
assert bond_2_divs.count() == 1
container_div = self.page.locator("#container")
# Make sure that the clones are rendered in the right order
assert container_div.inner_text() == "Bond\nJames\nBond"
def test_element_remove_single_class(self):
"""Test the element remove_class"""
self.pyscript_run(
"""
<div id="foo" class="bar baz"></div>
<py-script>
from pyscript import Element
el = Element("foo")
el.remove_class("bar")
</py-script>
"""
)
assert self.console.log.lines[0] == self.PY_COMPLETE
div = self.page.locator("#foo")
assert div.get_attribute("class") == "baz"
def test_element_remove_multiple_classes(self):
"""Test the element remove_class"""
self.pyscript_run(
"""
<div id="foo" class="foo bar baz"></div>
<py-script>
from pyscript import Element
el = Element("foo")
el.remove_class(["foo", "baz", "bar"])
</py-script>
"""
)
assert self.console.log.lines[0] == self.PY_COMPLETE
div = self.page.locator("#foo")
assert div.get_attribute("class") == ""
def test_element_add_single_class(self):
"""Test the element add_class"""
self.pyscript_run(
"""
<style> .red { color: red; } </style>
<div id="foo">Hi!</div>
<py-script>
from pyscript import Element
el = Element("foo")
el.add_class("red")
</py-script>
"""
)
assert self.console.log.lines[0] == self.PY_COMPLETE
div = self.page.locator("#foo")
assert div.get_attribute("class") == "red"
def test_element_add_multiple_class(self):
"""Test the element add_class"""
self.pyscript_run(
"""
<style> .red { color: red; } .bold { font-weight: bold; } </style>
<div id="foo">Hi!</div>
<py-script>
from pyscript import Element
el = Element("foo")
el.add_class(["red", "bold"])
</py-script>
"""
)
assert self.console.log.lines[0] == self.PY_COMPLETE
div = self.page.locator("#foo")
assert div.get_attribute("class") == "red bold"