Core feature of Wheezy HTML is WidgetFactory. This class has shortcut widget. You instantiate WidgetFactory and pass the following arguments:
Let declare our domain model:
class Credential(object):
def __init__(self):
self.username = ''
self.password = ''
This way we get HTML widget:
from wheezy.html import widget
credential = Credential()
errors = {}
credential = widget(credential, errors)
Each attribute in widget corresponds to appropriate attribute in model. Attribute name becomes name in html element. Convention for html id is replace underscope with dash. So attribute confirm_password remains unchanged in html name, however id will be confirm-password.
Once we know name of html widget, next pass control to appropriate widget for rendering:
credential.username.textbox(autocomplete='off')
Let explain this single line:
Once that code is executed we get the following:
<input autocomplete="off" type="text" id="username"
value="" name="username" />
You can format model value before it is passed to widget for rendering.
Let declare our domain model:
from datetime import date
class Registration(object):
def __init__(self):
self.date_of_birth = date.min
Here is how you can apply formatting:
registration.date_of_birth.format('%Y/%m/%d')
or this way:
registration.date_of_birth.format(
format_provider=lambda value, ignore: value.strftime('%m-%d-%y'))
Widget formatting can follow by actual widget that needs to be rendered:
registration.date_of_birth.format('%Y/%m/%d').textbox()
format_provider - a callable of the following form:
def my_format_provider(value, format_string):
return value_formatted
There are default format providers for built-in types. You can replace and extend it with your own by altering format_providers map:
from wheezy.html.utils import format_providers
format_providers['my_type'] = my_format_provider
Default implementation for date/time types formats it minimal value to empty string.
Since widget is initialized with model and errors, it capable to decorate html widget with attributes specific to errors. Let see this in the following example:
errors = {'username': ['Required field cannot be left blank.']}
We get the errors from some sort of validation. The same textbox is now decorated with class error:
<input name="username" value="" autocomplete="off"
class="error" type="text" id="username" />
So I can apply appropriate css style to draw a border around input, or what ever else since in html I have distinguished situation between input with error and with valid input.
Now let display error:
credential.username.error()
Read above as render error message for username, here is what we get:
<span class="error">Required field cannot be left blank.</span>
General error is not related to certain model attribute but to operation related instead. If errors dictionary contains an element with __ERROR__ key than that one is used as general error:
errors = {'__ERROR__': 'The username or password provided is incorrect.'}
You can display it this way:
credential.error()
It renders the following html element only if __ERROR__ key exists:
<span class="error-message">The username or password
provided is incorrect.</span>
Notice class error-message. Your application is able to distinguish field errors from general errors.
Wheezy HTML comes with a number of built-in widgets. They can be generally divided into two categories with support of a single value (string, int, datetime, etc) or multiple (list or tuple).
Single value widgets:
Widgets that support multiple values:
Several widgets support choinces attribute, it is an iteratable of tuple of two:
account_types = (('u', 'User'), ('b', 'Business'))
account.account_type.radio(choices=account_types)
It renders the following html:
<label><input checked="checked" type="radio"
name="account_type" value="1" />User</label>
<label><input type="radio" name="account_type"
value="2" />Business</label>
It is sometimes more convinient to operate with dictionary:
>>> from operator import itemgetter
>>> account_types = sorted({'u': 'User', 'b': 'Business'}.items(),
... key=itemgetter(1))
>>> account_types
[('u', 'User'), ('b', 'Business')]
It is easy to provide own widgets. A widget is any callable of the following contract:
from wheezy.html.markup import Tag
def my_widget(name, value, attrs):
tag_attrs = {
'id' = id(name)
}
if attrs:
tag_attrs.update(attrs)
return Tag('name', value, attrs=tag_attrs)
Here is a description of each attribute:
Your custom widget must return an instance of Tag or Fragment. In case of field error html element is decorated with css class error.
Once my_widget is ready you can add it to a list of default widgets:
from wheezy.html.widgets import default as default_widgets
default_widgets['my_widget'] = my_widget
Now you should be able to use it:
credential.username.my_widget()
Since default_widgets is python dictionary you can manipulate it a way you like.
Wheezy HTML integrates with the following template systems:
Wheezy HTML integration with Jinja2 is provided via extension feature. Here is how to add WidgetExtension() to your code:
from wheezy.html.ext.jinja2 import WidgetExtension
env = Environment(
...
extensions=[WidgetExtension])
The only thing WidgetExtension() does is translation of widget code to adequate Jinja2 code.
Let demonstrate with by example:
{{ model.remember_me.checkbox() }}
is translated to the following Jinja2 code (during template compilation phase):
<input id="remember-me" name="remember_me" type="checkbox"
value="1"
{% if 'remember_me' in errors: %}
class="error"
{% endif %}
{% if model.remember_me: %}
checked="checked"
{% endif %} />
which effectively renders the HTML at runtime:
<input id="remember-me" name="remember_me" type="checkbox" value="1" />
Since widgets also decorate appropriate HTML tags in case of error, errors dictionary must be available in Jinja2 context:
template = env.get_template(template_name)
assert 'errors' in kwargs
template.render(
**kwargs
)
See wheezy.html.ext.mako for more examples.
Wheezy HTML integration with Mako is provided via preprocessor feature. Here is how to add widget_preprocessor() to your code:
from wheezy.html.ext.mako import widget_preprocessor
template_lookup = TemplateLookup(
...
preprocessor=[widget_preprocessor])
The only thing widget_preprocessor() does is translation of widget code to adequate Mako code.
Let demonstrate with by example:
${model.remember_me.checkbox()}
is translated to the following Mako code (during template compilation phase):
<input id="remember-me" name="remember_me" type="checkbox" value="1"\
% if 'remember_me' in errors:
class="error"\
% endif
% if model.remember_me:
checked="checked"\
% endif
/>
which effectively renders the HTML at runtime:
<input id="remember-me" name="remember_me" type="checkbox" value="1" />
Since widgets also decorate appropriate HTML tags in case of error, errors dictionary must be available in Mako context:
template = template_lookup.get_template(template_name)
assert 'errors' in kwargs
template.render(
**kwargs
)
See wheezy.html.ext.mako for more examples.
Wheezy HTML integration with Tenjin is provided via preprocessor feature. Here is how to add widget_preprocessor() to your code:
from wheezy.html.ext.tenjin import widget_preprocessor
engine = tenjin.Engine(
...
pp=[widget_preprocessor])
The only thing widget_preprocessor() does is translation of widget code to adequate Tenjin code.
Let demonstrate with by example:
${model.remember_me.checkbox(class_='i')}
is translated to the following Tenjin code (during template compilation phase):
<input id="remember-me" name="remember_me" type="checkbox" value="1"<?py #pass ?>
<?py if 'remember_me' in errors: ?>
class="error i"<?py #pass ?>
<?py else: ?>
class="i"<?py #pass ?>
<?py #endif ?><?py if model.remember_me: ?>
checked="checked"<?py #pass ?>
<?py #endif ?>
/>
which effectively renders the HTML at runtime:
<input id="remember-me" name="remember_me" type="checkbox" value="1" class="i" />
Since widgets also decorate appropriate HTML tags in case of error, errors dictionary must be available in Tenjin context:
assert 'errors' in kwargs
engine.render('page.html',
**kwargs
)
See wheezy.html.ext.tenjin for more examples.
Wheezy HTML integration with wheezy.template is provided via preprocessor feature. Here is how to add WidgetExtension() to your code:
from wheezy.html.ext.template import WidgetExtension
from wheezy.html.utils import html_escape
from wheezy.html.utils import format_value
engine = Engine(
...
extensions=[
WidgetExtension
])
engine.global_vars.update({
'format_value': format_value,
'h': html_escape
})
The only thing WidgetExtension() does is translation of widget code to adequate wheezy.template code.
Let demonstrate with by example:
@model.remember_me.checkbox(class_='i')
is translated to the following wheezy.template code (during template compilation phase):
<input id="remember-me" name="remember_me" type="checkbox" value="1"
@if 'remember_me' in errors:
class="error i"
@else:
class="i"
@if model.remember_me:
checked="checked"
@end
/>
which effectively renders the HTML at runtime:
<input id="remember-me" name="remember_me" type="checkbox" value="1" class="i" />
Since widgets also decorate appropriate HTML tags in case of error, errors dictionary must be available in wheezy.template context:
assert 'errors' in kwargs
engine.render('page.html',
**kwargs
)
See wheezy.html.ext.template for more examples.