Basic DOM Features

First Example

Program to show "Hello, WDOM" on browser is:

from wdom.document import get_document
from wdom.server import start

if __name__ == '__main__':
    document = get_document()
    h1 = document.createElement('h1')
    h1.textContent = 'Hello, WDOM'
    document.body.appendChild(h1)
    start()

Save and execute code and access http://localhost:8888 by browser. Then, web page with "Hello, WDOM" will be shown.

The four lines beginning from document = get_document() are very similar to JavaScript. document returned by get_document() is a Document Node, equivalent to document object in JavaScript on browsers. document.createElement('{tag-name}') generates new element with the given tag-name. appendChild method inserts the child node at the last of its child nodes. Not used in the sample code, by using removeChild method, one can remove the child node.

Model of WDOM Elements

GUI elements of the WDOM are composed of HTML tags (elements or nodes) on a browser. Usually they have one-by-one relationships: thus document.createElement('h1') returns one WDOM element, and it is rendered as an <h1> tag on a browser. All WDOM elements have their own HTML representations, which can be obtained by their html property.

Elements created by WDOM are all based on DOM Living Standard and related standards (HTML Living Standard, CSS Object Model, DOM Parsing, and Custom Elements in WebComponents).

As elements are modeled by DOM, you can add/remove/replace them as same as the way in JavaScript on browsers. Currently, not all of DOM features have been implemented in WDOM, but lots of frequently-used methods/properties are available. Implemented features are listed in wiki pages at gihub.

Create New Element

To make elements, WDOM provides two methods.

One is document.createElement mentioned above, and the other is to instantiate classes defined in wdom.tag module. For details about the wdom.tag module, see Python Classes and Extensions of WDOM section.

Note

Every element does not appear on browser until inserted to the DOM tree which roots on the document node returned by get_document().

Append/Insert Node

To insert nodes on the DOM tree, use appendChild or insertBefore method. A.appendChild(B) append the node B at last of child nodes of the parent node A. A.insertBefore(B, C) inserts new element B just before the reference node C. The reference node C must be a child node of the parent node A.

These method names are quite long, so some methods specified in DOM specification are also available on WDOM: prepend, append, before, after, and replaceWith. Details about these methods are described in Newest DOM Features section.

Remove Node

It is also able to remove child node from the DOM tree.

A.removeChild(B) removes the child node B from the parent node A. If B is not a child node of A, it will raise Error.

More simple method B.remove() is also available, see Newest DOM Features section.

Access Child/Parent/Sibling Nodes

childNodes property returns list-like live-object which contains its direct child nodes. firstChild and lastChild property returns its first/last child node.

On the other way, parentNode property returns its parent node. These properties are same as JavaScript’s DOM.

nextSibling and previousSibling returns its next/previous sibling node.

If there is no corresponding node, all these properties return None.

Attributes

To get element’s attributes like class="..." in HTML tag, use getAttribute('attribute-name') method. If called getAttribute to the attribute which does not exists, it will return None.

To set or change attribute’s value, use setAttribute('attribute-name', value) method. And to remove an attribute, use removeAttribute method.

To obtain all attributes set for the element, access attributes property. This property returns dictionary-like abject NamedNodeMap. This object has attributes and its value as {'attribute-name': value, ...}.

Special Attributes

Some attributes are accessible via special properties, for exmaple, A.id returns its ID attribute. Available properties will be found in wiki page at gihub.

With getAttribute returns string or None, but attributes accessed via its properties return different types depending on its property. For example, element.id return always string even if it is not set (in case id is not set, element.id returns empty string, not None). Similarly, element.hidden returns boolean (True or False) and element.style returns CSSStyleDeclaration.

Style Attribute (CSSStyleDeclaration)

CSSStyleDeclaration obtained by element.style provides property access to its css properties. For example, element.style.color = 'red' makes element’s color red.

Some css properties including hyphen (-) will be converted to CamelCase name. For example, background-color will become element.style.backgroundColor. For more examples, please see CSS Properties Reference

Using HTML

Making large applications with appendChild and insertBefore are quite difficult. So writing HTML and parse it to WDOM elements is sometimes useful.

It can be done by innerHTML method, as same as JavaScript. An example to make large list is below:

from wdom.tag import Ul

ul = Ul()
ul.innerHTML = '''\
<li>item1</li>
<li>item2</li>
<li>item3</li>
<li>item4</li>
'''

print(ul.html_noid)  # <ul><li>...

# Accessing child nodes
# for child in ul.childNodes:
#     print(child.html)

# or, first/lastChild
print(ul.firstChild.html)
print(ul.lastChild.html)

# excluding Text nodes
for child in ul.children:
    print(child.html)

# first/lastElementChild
print(ul.firstElementChild.html)
print(ul.lastElementChild.html)

Note

Assignment to innerHTML removes all child nodes and insert parsed elements.

Each child nodes can be accessed via childNodes property, which returns list-like live-object, but not able to modify its values.

insertAdjacentHTML({position}, {html}) also parses HTML and insert new elements to the position. This method is also same as JavaScript’s one, so for details please see MDN Element.insertAdjacentHTML() or DOM specification.

outerHTML is not implemented in WDOM.

Event Handling

Reverse Text on Click

WDOM’s event handling is also same as JavaScript:

from wdom.server import start
from wdom.document import get_document

if __name__ == '__main__':
    document = get_document()
    h1 = document.createElement('h1')
    h1.textContent = 'Hello, WDOM'
    def rev_text(event):
        h1.textContent = h1.textContent[::-1]
    h1.addEventListener('click', rev_text)
    document.body.appendChild(h1)
    start()

Run this code and click "Hello, WDOM". Then it will be reversed. When clicked again, it will be reversed again and back to "Hello, WDOM".

addEventListener('{event-type}', {handler}) method registers handler to the given event-type. In the sample code, rev_text function is registered to click event. Values available for event type are same as JavaScript’s DOM, as listed in Event reference | MDN.

When the h1 element is clicked, registered function rev_text is called with a single argument, event, which is an Event object, though it is not used in the above example.

User Input Event

The below sample shows how to use event object:

from wdom.document import get_document
from wdom.server import start

if __name__ == '__main__':
    document = get_document()
    h1 = document.createElement('h1')
    h1.textContent = 'Hello, WDOM'
    input = document.createElement('textarea')
    def update(event):
        h1.textContent = event.target.value
    input.addEventListener('input', update)
    document.body.appendChild(input)
    document.body.appendChild(h1)
    start()

In this sample, textarea element is added. When user inputs some text on the textarea, it will be shown as h1 element.

In the update function, event.target has a reference to the element which emitted the event, in this case it is a textarea element. And, as same as JavaScript, a textarea element (and input element) contains its current value at value attribute. At the moment update function is called, textarea.value is already updated to the latest value. So the above code you can use textarea.value instead of event.target.value. In the sample code, setting its value to h1 element’s textContent.