Basic DOM Features
==================
First Example
-------------
Program to show `"Hello, WDOM"` on browser is:
.. literalinclude:: samples/dom1.py
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 `
` 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](https://dom.spec.whatwg.org/) and related standards ([HTML Living
Standard](https://html.spec.whatwg.org/multipage/), [CSS Object
Model](https://drafts.csswg.org/cssom/), [DOM
Parsing](https://w3c.github.io/DOM-Parsing/), and [Custom Elements in
WebComponents](http://w3c.github.io/webcomponents/spec/custom/)).
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](https://github.com/miyakogi/wdom/wiki/Features).
### 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 :doc:`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
:doc:`new_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 :doc:`new_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](https://github.com/miyakogi/wdom/wiki/Features).
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`.
* References
* [HTMLElement | MDN](https://developer.mozilla.org/en/docs/Web/API/HTMLElement)
* [element.id | MDN](https://developer.mozilla.org/ja/docs/Web/API/Element/id)
* [element.style | MDN](https://developer.mozilla.org/ja/docs/Web/API/HTMLElement/style)
### 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](https://developer.mozilla.org/en-US/docs/Web/CSS/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:
.. literalinclude:: samples/dom2.py
.. 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()](https://developer.mozilla.org/en-US/docs/Web/API/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:
.. literalinclude:: samples/dom3.py
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](https://developer.mozilla.org/en-US/docs/Web/Events).
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:
.. literalinclude:: samples/dom4.py
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`.
.. _DOM specification: https://dom.spec.whatwg.org/