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 wdom_id="..."><input wdom_id="..."><h1 wdom_id="...">Hello, WDOM</h1></div>
wdom_id is an attribute which 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)