Python Classes and Extensions of WDOM

Generating new elements by document.createElement every time is quite mess. So WDOM’s wdom.tag module provides simple tag classes usually used.

By using tag classes, the previous example can be written as:

from wdom.document import set_app
from wdom.server import start
from wdom.tag import Div, H1, Input

class MyElement(Div):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.h1 = H1()
        self.h1.textContent = 'Hello, WDOM'
        self.input = Input()
        self.input.addEventListener('input', self.update)
        self.appendChild(self.input)
        self.appendChild(self.h1)

    def update(self, event):
        self.h1.textContent = event.target.value

if __name__ == '__main__':
    set_app(MyElement())
    server = start()

Instead of using document.createElement, in the above example is using H1 class and Input class to generate h1 element and input element. Furthermore, MyElement class inherits Div class. Its instance is rendered as div element, or <div> tag on a browser. These instances are same as instances generated by document.createElement method.

Names of pre-defined classes on wdom.tag module are same as related tag names, starting with upper-case and followed by lower-case. For example, <button> tag is Button class, <br> tag is Br class, and <textarea> tag is Textarea.

Actual HTML strings can be obtained by html property of each elements. For example, print(MyElement().html) shows

<div rimo_id="..."><input rimo_id="..."><h1 rimo_id="...">Hello, WDOM</h1></div>

rimo_id attribute is used internally. If you want to omit it for tests, use html_noid property instead

print(MyElement().html_noid)
# -> <div><input><h1>Hello, WDOM</h1></div>

Append to Parent Node

By using parent argument of constructor, newly generated elements will be automatically appended to the parent node. Using this, the above example can be written as:

from wdom.server import start
from wdom.document import set_app
from wdom.tag import Div, H1, Input

class MyElement(Div):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.h1 = H1(parent=self)
        self.h1.textContent = 'Hello, WDOM'
        self.input = Input(parent=self)
        self.input.addEventListener('input', self.update)

    def update(self, event):
        self.h1.textContent = event.target.value

if __name__ == '__main__':
    set_app(MyElement())
    start()

At the line self.h1 = H1(parent=self), new h1 element is automatically appended to self as its child node.

Append Child Nodes

In the other way, child nodes can be appended on generation.

from wdom.document import set_app
from wdom.server import start
from wdom.tag import Div, H1, Input

class MyElement(Div):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.h1 = H1('Hello, WDOM', parent=self)  
        self.input = Input(parent=self)
        self.input.addEventListener('input', self.update)

    def update(self, event):
        self.h1.textContent = event.target.value

if __name__ == '__main__':
    set_app(MyElement())
    start()

At the self.h1 = H1('Hello, WDOM', parent=self), the first argument is converted to Text Node and appended to the newly generated h1 element. With multiple arguments, more than one child node can be appended, like H1(H2(), P(), ...).

Initialization with Attributes

Attributes are also able to be defined with keyword arguments on the constructor.

from wdom.tag import Input

input = Input(type='checkbox')
print(input.html_noid)  # <input type="checkbox">

# this is equivalent to:
input = Input()
input.setAttribute('type', 'checkbox')
# also same as:
input.type = 'checkbox'

class is a python’s keyword, so use class_ (trailing underscore) instead.

from wdom.tag import H1

h1 = H1(class_='title')
print(h1.html_noid)  # <h1 class="title"></h1>

# this is equivalent to:
h1 = H1()
h1.setAttribute('class', 'title')
# also same as:
h1.classList.add('title')
# classList.add accepts mutliple arguments
h1.classList.add('title', 'heading', '...', )

Default Class Attribute

User-defined class can have default class attributes.

from wdom.tag import Button

class MyButton(Button):
    class_ = 'btn'

print(MyButton().html_noid)
# <button class="btn"></button>

# This is almost same as:
class MyButton2(Button):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setAttribute('class', 'btn')
        ...

# class-level classes are not able to remove from instance
btn = MyButton()
btn.classList.remove('btn')
print(btn.html_noid)  # <button class="btn"></button>

btn2 = MyButton2()
btn2.classList.remove('btn')
print(btn2.html_noid)  # <button></button>

# Inherited class_ not overrides super-classes class_
class DefaultButton(MyButton):
    class_ = 'btn-default'

db = DefaultButton()
print(db.html_noid)  # <button class="btn btn-default"></button>

class_ class-variable is added to the instance. This attribute cannot be removed at its instance and it is inherited to the subclasses. If you don’t want to inherit parent’s class attributes, add inherit_class = False as a class variable.

Shortcut of Class Definition

Defining lots of similar classes by class statement is quite mess. WDOM provides wdom.tag.NewTagClass function to make new user-defined classes.

MyButton class and DefaultButton class defined in the above example can be defined simply by using NewTagClass function as below:

from wdom.tag import Button, NewTagClass

# Making new class easily
MyButton = NewTagClass('MyButton', 'button', Button, class_='btn')
DefaultButton = NewTagClass('DefaultButton', 'button', MyButton, class_='btn-default')

print(MyButton().html_noid)
print(DefaultButton().html_noid)

The first argument is a name of new class, the second is a tag name, the third is a base class, and the firth and other keyword arguments are class-variables of the new class. To inherit multiple classes, use tuple at the third argument.

These features are not DOM standard and specially defined for WDOM.

Execute JavaScript on Browser

(to be written)