Helpers YATL
Helpers overview
Consider the following code in a template:
[[=DIV('this', 'is', 'a', 'test', _id='123', _class='myclass')]]
ele é processado como:
<div id="123" class="myclass">thisisatest</div>
You can easily test the rendering of these commands by copying the _scaffold app (see
Copying the _scaffold app) and then editing the file
new_app/template/index.html
.
DIV
is a helper class, i.e., something that can be used to build
HTML programmatically. It corresponds to the HTML <div>
tag.
Helpers can have:
positional arguments interpreted as objects contained between the open and close tags, like
thisisatest
in the previous examplenamed arguments (start with an underscore) interpreted as HTML tag attributes (without the underscore), like
_class
and_id
in the previous examplenamed arguments (start without an underscore), in this case these arguments are tag-specific
Em vez de um conjunto de argumentos sem nome, um helper também pode ter uma única lista ou tupla como seu conjunto de componentes usando a notação `` * `` e pode levar um único dicionário como seu conjunto de atributos usando o `` ** ` `, por exemplo:
[[
contents = ['this', 'is', 'a', 'test']
attributes = {'_id':'123', '_class':'myclass'}
=DIV(*contents, **attributes)
]]
(Produz a mesma saída que antes).
The following are the current set of helpers available within the YATL module:
A
, BEAUTIFY
, BODY
, CAT
, CODE
, DIV
, EM
,
FORM
, H1
, H2
, H3
, H4
, H5
, H6
, HEAD
,
HTML
, IMG
, INPUT
, LABEL
, LI
, METATAG
,
OL
, OPTION
, P
, PRE
, SELECT
, SPAN
, STRONG
,
TABLE
, TAG
, TAGGER
, THEAD
, TBODY
, TD
,
TEXTAREA
, TH
, TT
, TR
, UL
, XML
, xmlescape
,
I
, META
, LINK
, TITLE
, STYLE
, SCRIPT
Helpers can be used to build complex expressions, that can then be serialized to XML. For example:
[[=DIV(STRONG(I("hello ", "<world>")), _class="myclass")]]
é prestado:
<div class="myclass"><strong><i>hello <world></i></strong></div>
Helpers can also be serialized into strings, equivalently, with the
__str__
and the xml
methods. This can be manually tested directly
with a Python shell or by using the Opção `` comando shell`` of py4web
and then:
>>> from yatl.helpers import *
>>>
>>> str(DIV("hello world"))
'<div>hello world</div>'
>>> DIV("hello world").xml()
'<div>hello world</div>'
The helpers mechanism in py4web is more than a system to generate HTML without concatenating strings. It provides a server-side representation of the document object model (DOM).
Componentes de helpers podem ser referenciados através de sua posição, e helpers agir como listas com relação aos seus componentes:
>>> a = DIV(SPAN('a', 'b'), 'c')
>>> print(a)
<div><span>ab</span>c</div>
>>> del a[1]
>>> a.append(STRONG('x'))
>>> a[0][0] = 'y'
>>> print(a)
<div><span>yb</span><strong>x</strong></div>
Atributos de helpers pode ser referenciado pelo nome, e helpers agir como dicionários com relação aos seus atributos:
>>> a = DIV(SPAN('a', 'b'), 'c')
>>> a['_class'] = 's'
>>> a[0]['_class'] = 't'
>>> print(a)
<div class="s"><span class="t">ab</span>c</div>
Note, the complete set of components can be accessed via a list called
a.children
, and the complete set of attributes can be accessed via
a dictionary called a.attributes
. So, a[i]
is equivalent to
a.children[i]
when i
is an integer, and a[s]
is equivalent
to a.attributes[s]
when s
is a string.
Note que atributos auxiliares são passados como argumentos para o auxiliar. Em alguns casos, no entanto, nomes de atributos incluem caracteres especiais que não são permitidos em identificadores Python (por exemplo, hífens) e, portanto, não podem ser usados como nomes de argumentos de palavra-chave. Por exemplo:
DIV('text', _data-role='collapsible')
will not work because “_data-role” includes a hyphen, which will produce a Python syntax error.
In such cases you can pass the attributes as a dictionary and make use
of Python’s **
function arguments notation, which maps a dictionary
of (key:value) pairs into a set of keyword arguments:
>>> print(DIV('text', **{'_data-role': 'collapsible'}))
<div data-role="collapsible">text</div>
Você também pode criar dinamicamente tags especiais:
>>> print(TAG['soap:Body']('whatever', **{'_xmlns:m':'http://www.example.org'}))
<soap:Body xmlns:m="http://www.example.org">whatever</soap:Body>
Built-in helpers
`` XML``
XML
is an helper object used to encapsulate text that should not be
escaped. The text may or may not contain valid XML; for example it
could contain JavaScript.
O texto neste exemplo é escapado:
>>> print(DIV("<strong>hello</strong>"))
<div><strong>hello</strong></div>
usando `` XML`` você pode impedir escapar:
>>> print(DIV(XML("<strong>hello</strong>")))
<div><strong>hello</strong></div>
Às vezes você quer renderizar HTML armazenado em uma variável, mas o HTML pode conter tags inseguras como scripts:
>>> print(XML('<script>alert("unsafe!")</script>'))
<script>alert("unsafe!")</script>
Un-escaped executable input such as this (for example, entered in the
body of a comment in a blog) is unsafe, because it can be used to
generate cross site scripting (XSS) attacks against other visitors to
the page.
In this case the py4web XML
helper can sanitize our text to prevent injections
and escape all tags except those that you explicitly allow. Here is an
example:
>>> print(XML('<script>alert("unsafe!")</script>', sanitize=True))
<script>alert("unsafe!")</script>
Os `` construtores XML``, por padrão, considere o conteúdo de algumas tags e alguns de seus atributos de segurança. Você pode substituir os padrões usando os opcionais `` permitted_tags`` e `` allowed_attributes`` argumentos. Aqui estão os valores padrão dos argumentos opcionais do `` helper XML``.
XML(text, sanitize=False,
permitted_tags=['a', 'b', 'blockquote', 'br/', 'i', 'li',
'ol', 'ul', 'p', 'cite', 'code', 'pre', 'img/',
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'table', 'tr', 'td',
'div', 'strong', 'span'],
allowed_attributes={'a': ['href', 'title', 'target'],
'img': ['src', 'alt'], 'blockquote': ['type'], 'td': ['colspan']})
`` A``
Este assistente é usado para construir ligações.
>>> print(A('<click>', XML('<strong>me</strong>'),
_href='http://www.py4web.com'))
<a href="http://www.py4web.com"><click><strong>me</strong></a>
`` BODY``
Este assistente faz com que o corpo de uma página.
>>> print(BODY('<hello>', XML('<strong>world</strong>'), _bgcolor='red'))
<body bgcolor="red"><hello><strong>world</strong></body>
`` CAT``
This helper concatenates other helpers.
>>> print(CAT('Here is a ', A('link', _href='target'), ', and here is some ', STRONG('bold text'), '.'))
Here is a <a href="target">link</a>, and here is some <strong>bold text</strong>.
`` Div``
This is the content division element.
>>> print(DIV('<hello>', XML('<strong>world</strong>'), _class='test', _id=0))
<div id="0" class="test"><hello><strong>world</strong></div>
`` EM``
Insiste no seu conteúdo.
>>> print(EM('<hello>', XML('<strong>world</strong>'), _class='test', _id=0))
<em id="0" class="test"><hello><strong>world</strong></em>
`` Form``
Use this helper to make a FORM for user input. Forms will be later discussed in detail in the dedicated Forumlários chapter.
>>> print(FORM(INPUT(_type='submit'), _action='', _method='post'))
<form action="" method="post"><input type="submit"/></form>
`` H1``, `` h2``, `` H3``, `` H4``, `` H5``, `` H6``
These helpers are for paragraph headings and subheadings.
>>> print(H1('<hello>', XML('<strong>world</strong>'), _class='test', _id=0))
<h1 id="0" class="test"><hello><strong>world</strong></h1>
`` HEAD``
Para marcar a cabeça de uma página HTML.
>>> print(HEAD(TITLE('<hello>', XML('<strong>world</strong>'))))
<head><title><hello><strong>world</strong></title></head>
`` HTML``
For tagging an HTML page.
>>> print(HTML(BODY('<hello>', XML('<strong>world</strong>'))))
<html><body><hello><strong>world</strong></body></html>
`` I``
Este assistente torna o seu conteúdo em itálico.
>>> print(I('<hello>', XML('<strong>world</strong>'), _class='test', _id=0))
<i id="0" class="test"><hello><strong>world</strong></i>
`` IMG``
It can be used to embed images into HTML.
>>> print(IMG(_src='http://example.com/image.png', _alt='test'))
<img alt="test" src="http://example.com/image.png"/>
Aqui é uma combinação de helpers A, IMG, e URL para a inclusão de uma imagem estática com um link:
>>> print(A(IMG(_src=URL('static', 'logo.png'), _alt="My Logo"),
... _href=URL('default', 'index')))
<a href="/default/index"><img alt="My Logo" src="/static/logo.png"/></a>
`` INPUT``
Cria um `` <input … /> `` tag. Uma tag de entrada não pode conter outras tags, e é fechada por `` /> `` em vez de > ``. A tag de entrada tem um atributo opcional `` _type
que pode ser definido como “texto” (o padrão), “enviar”, “caixa”, ou “rádio”.
>>> print(INPUT(_name='test', _value='a'))
<input name="test" value="a"/>
For radio buttons use the _checked
attribute:
>>> for v in ['a', 'b', 'c']:
... print(INPUT(_type='radio', _name='test', _value=v, _checked=v=='b'), v)
...
<input name="test" type="radio" value="a"/> a
<input checked="checked" name="test" type="radio" value="b"/> b
<input name="test" type="radio" value="c"/> c
e similarmente para caixas de seleção:
>>> print(INPUT(_type='checkbox', _name='test', _value='a', _checked=True))
<input checked="checked" name="test" type="checkbox" value="a"/>
>>> print(INPUT(_type='checkbox', _name='test', _value='a', _checked=False))
<input name="test" type="checkbox" value="a"/>
`` Label``
Ele é usado para criar uma tag rótulo para um campo de entrada.
>>> print(LABEL('<hello>', XML('<strong>world</strong>'), _class='test', _id=0))
<label id="0" class="test"><hello><strong>world</strong></label>
`` LI``
Faz um item da lista e deve estar contido em um `` UL`` ou `` tag OL``.
>>> print(LI('<hello>', XML('<strong>world</strong>'), _class='test', _id=0))
<li id="0" class="test"><hello><strong>world</strong></li>
`` OL``
It stands for ordered list. The list should contain LI tags.
>>> print(OL(LI('<hello>'), LI(XML('<strong>world</strong>')), _class='test', _id=0))
<ol class="test" id="0"><li><hello></li><li><strong>world</strong></li></ol>
`` OPTION``
This should only be used as argument of a SELECT
.
>>> print(OPTION('<hello>', XML('<strong>world</strong>'), _value='a'))
<option value="a"><hello><strong>world</strong></option>
For selected options use the _selected
attribute:
>>> print(OPTION('Thank You', _value='ok', _selected=True))
<option selected="selected" value="ok">Thank You</option>
`` P``
Isto é para marcar um parágrafo.
>>> print(P('<hello>', XML('<strong>world</strong>'), _class='test', _id=0))
<p id="0" class="test"><hello><strong>world</strong></p>
`` PRE``
Gera um `` <pre> … </ pre> `` tag para exibir texto pré-formatado. O `` CODE`` auxiliar é geralmente preferível para listagens de código.
>>> print(SELECT(OPTION('first', _value='1'), OPTION('second', _value='2'), _class='test', _id=0))
<pre id="0" class="test"><hello><strong>world</strong></pre>
`` SCRIPT``
This is for include or link a script, such as JavaScript.
>>> print(SCRIPT('console.log("hello world");', _type='text/javascript'))
<script type="text/javascript">console.log("hello world");</script>
`` SELECT``
Makes a <select>...</select>
tag. This is used with the OPTION
helper.
>>> print(SELECT(OPTION('first', _value='1'), OPTION('second', _value='2'),
... _class='test', _id=0))
<select class="test" id="0"><option value="1">first</option><option value="2">second</option></select>
`` SPAN``
Semelhante a `` div`` mas utilizado para marcação em linha (em vez de bloco) conteúdo.
>>> print(SPAN('<hello>', XML('<strong>world</strong>'), _class='test', _id=0))
<span id="0" class="test"><hello><strong>world</strong></span>
`` STYLE``
Semelhante ao script, mas usadas para incluir ou código do link CSS. Aqui, o CSS está incluído:
>>> print(STYLE(XML('body {color: white}')))
<style>body {color: white}</style>
e aqui ela está ligada:
>>> print(STYLE(_src='style.css'))
<style src="style.css"></style>
`` TABLE``, `` TR``, `` TD``
Estas tags (juntamente com o opcional `` THEAD`` e `` helpers TBODY``) são utilizados para tabelas de construção HTML.
>>> print(TABLE(TR(TD('a'), TD('b')), TR(TD('c'), TD('d'))))
<table><tr><td>a</td><td>b</td></tr><tr><td>c</td><td>d</td></tr></table>
TR
expects TD
content.
É fácil converter uma matriz de Python em uma tabela HTML usando `` * `` notação argumentos de função do Python, que mapeia os elementos da lista para os argumentos da função posicionais.
Aqui, vamos fazê-lo linha por linha:
>>> table = [['a', 'b'], ['c', 'd']]
>>> print(TABLE(TR(*map(TD, table[0])), TR(*map(TD, table[1]))))
<table><tr><td>a</td><td>b</td></tr><tr><td>c</td><td>d</td></tr></table>
Aqui nós fazer todas as linhas de uma só vez:
>>> table = [['a', 'b'], ['c', 'd']]
>>> print(TABLE(*[TR(*map(TD, rows)) for rows in table]))
<table><tr><td>a</td><td>b</td></tr><tr><td>c</td><td>d</td></tr></table>
`` TBODY``
Isto é usado para linhas tag contidos no corpo de mesa, em oposição a linhas de cabeçalho ou de rodapé. É opcional.
>>> print(TBODY(TR(TD('<hello>')), _class='test', _id=0))
<tbody id="0" class="test"><tr><td><hello></td></tr></tbody>
`` TEXTAREA``
Este assistente faz uma <textarea> … </ textarea> tag ``.
>>> print(TEXTAREA('<hello>', XML('<strong>world</strong>'), _class='test',
... _cols="40", _rows="10"))
<textarea class="test" cols="40" rows="10"><hello><strong>world</strong></textarea>
`` TH``
Este é utilizado em vez de `` TD`` em cabeçalhos de tabela.
>>> print(TH('<hello>', XML('<strong>world</strong>'), _class='test', _id=0))
<th id="0" class="test"><hello><strong>world</strong></th>
`` THEAD``
Isto é usado para linhas de cabeçalho da tabela tag.
>>> print(THEAD(TR(TH('<hello>')), _class='test', _id=0))
<thead id="0" class="test"><tr><th><hello></th></tr></thead>
`` TITLE``
Isto é usado para marcar o título de uma página em um cabeçalho HTML.
>>> print(TITLE('<hello>', XML('<strong>world</strong>')))
<title><hello><strong>world</strong></title>
`` TT``
Etiquetas de texto como máquina de escrever texto (monoespaçada).
>>> print(TT('<hello>', XML('<strong>world</strong>'), _class='test', _id=0))
<tt id="0" class="test"><hello><strong>world</strong></tt>
`` UL``
It stands for unordered list. The list should contain LI tags.
>>> print(UL(LI('<hello>'), LI(XML('<strong>world</strong>')), _class='test', _id=0))
<ul class="test" id="0"><li><hello></li><li><strong>world</strong></li></ul>
`` URL``
The URL helper is not part of yatl package, instead it is provided by py4web.
Helpers personalizados
`` TAG``
Sometimes you need to generate custom XML tags*. For this purpose py4web
provides TAG
, a universal tag generator.
[[=TAG.name('a', 'b', _c='d')]]
gera o seguinte XML:
<name c="d">ab</name>
Argumentos “a”, “b” e “d” são automaticamente escapou; usar o `` helper XML`` para suprimir esse comportamento. Usando `` TAG`` você pode gerar HTML / XML marcas já não fornecidos pela API. As etiquetas podem ser aninhados, e são serializados com `` str () `` Uma sintaxe é equivalente.:
[[=TAG['name']('a', 'b', _c='d')]]
Tags com auto-fechamento podem ser geradas com o helper TAG. O noma da tag deve terminar com um “/”.
[[=TAG['link/'](_href='http://py4web.com')]]
gera o seguinte XML:
<link ref="http://py4web.com"/>
Notice that TAG
is an object, and TAG.name
or TAG['name']
is
a function that returns an helper instance.
`` BEAUTIFY``
`` BEAUTIFY`` é usado para representações de construção HTML de objetos compostos, incluindo listas, tuplas e dicionários:
[[=BEAUTIFY({"a": ["hello", STRONG("world")], "b": (1, 2)})]]
`` BEAUTIFY`` retorna um objeto serializado XML-like to XML, com uma representação de vista agradável de seu argumento construtor. Neste caso, a representação XML:
{"a": ["hello", STRONG("world")], "b": (1, 2)}
retribuirá como:
<table><tbody>
<tr><th>a</th><td><ul><li>hello</li><li><strong>world</strong></li></ul></td></tr>
<tr><th>b</th><td>(1, 2)</td></tr>
</tbody></table>
Server-side DOM
As we’ve already seen the helpers mechanism in py4web also provides a server-side representation of the document object model (DOM).
children
Each helper object keep the list of its components into the children
attribute.
>>> CAT('hello', STRONG('world')).children
['hello', <yatl.helpers.TAGGER object at 0x7fa533ff7640>]
find
To help searching into the DOM, all helpers have a find
method with
the following signature:
def find(self, query=None, **kargs)
that returns all the components matching supplied arguments.
A very simple query
can be a tag name:
>>> a = DIV(DIV(SPAN('x'), 3, DIV(SPAN('y'))))
>>> for c in a.find('span', first_only=True): c[0]='z'
>>> print(a) # We should .xml() here instead of print
<div><div><span>z</span>3<div><span>y</span></div></div></div>
>>> for c in a.find('span'): c[0]='z'
>>> print(a)
<div><div><span>z</span>3<div><span>z</span></div></div></div>
It also supports a syntax compatible with jQuery, accepting the following expressions:
jQuery Multiple Selector, e.g. “selector1, selector2, selectorN”,
jQuery Descendant Selector, e.g. “ancestor descendant”,
jQuery ID Selector, e.g. “#id”,
jQuery Class Selector, e.g. “.class”, and
jQuery Attribute Equals Selector, e.g. “[name=value]”, notice that here the value must be unquoted.
Here are some examples:
>>> a = DIV(SPAN(A('hello', **{'_id': '1-1', '_u:v': '$'})), P('world', _class='this is a test'))
>>> for e in a.find('div a#1-1, p.is'): print(e)
<a id="1-1" u:v="$">hello</a>
<p class="this is a test">world</p>
>>> for e in a.find('#1-1'): print(e)
<a id="1-1" u:v="$">hello</a>
>>> a.find('a[u:v=$]')[0].xml()
'<a id="1-1" u:v="$">hello</a>'
>>> a = FORM(INPUT(_type='text'), SELECT(OPTION(0)), TEXTAREA())
>>> for c in a.find('input, select, textarea'): c['_disabled'] = True
>>> a.xml()
'<form><input disabled="disabled" type="text"/><select disabled="disabled"><option>0</option></select><textarea disabled="disabled"></textarea></form>'
>>> for c in a.find('input, select, textarea'): c['_disabled'] = False
>>> a.xml()
'<form><input type="text"/><select><option>0</option></select><textarea></textarea></form>'
Elements that are matched can also be replaced or removed by specifying
a replace
argument (note, a list of the original matching elements
is still returned as usual).
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc'))))
>>> b = a.find('span.abc', replace=P('x', _class='xyz'))
>>> print(a)
<div><div><p class="xyz">x</p><div><p class="xyz">x</p><p class="xyz">x</p></div></div></div>
replace
can be a callable, which will be passed the original element and
should return a new element to replace it.
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc'))))
>>> b = a.find('span.abc', replace=lambda el: P(el[0], _class='xyz'))
>>> print(a)
<div><div><p class="xyz">x</p><div><p class="xyz">y</p><p class="xyz">z</p></div></div></div>
Se `` substituir = None``, os elementos correspondentes serão completamente removidas.
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc'))))
>>> b = a.find('span', text='y', replace=None)
>>> print(a)
<div><div><span class="abc">x</span><div><span class="abc"></span><span class="abc">z</span></div></div></div>
If a text
argument is specified, elements will be searched for text
components that match text, and any matching text components will be
replaced (text
is ignored if replace
is not also specified, use
a find
argument when you only need searching for textual elements).
Like the find
argument, text
can be a string or a compiled regex.
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc'))))
>>> b = a.find(text=re.compile('x|y|z'), replace='hello')
>>> print(a)
<div><div><span class="abc">hello</span><div><span class="abc">hello</span><span class="abc">hello</span></div></div></div>
If other attributes are specified along with text
, then only components
that match the specified attributes will be searched for text.
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='efg'), SPAN('z', _class='abc'))))
>>> b = a.find('span.efg', text=re.compile('x|y|z'), replace='hello')
>>> print(a)
<div><div><span class="abc">x</span><div><span class="efg">hello</span><span class="abc">z</span></div></div></div>
Using Inject
Normally all the code should be called from the controller program, and only the necessary data is passed to the template in order to be displayed. But sometimes it’s useful to pass variables or even use a python function as a helper called from a template.
In this case you can use the fixture Inject
from py4web.utils.factories.
This is a simple example for injecting a variable:
from py4web.utils.factories import Inject
my_var = "Example variable to be passed to a Template"
...
@unauthenticated("index", "index.html")
@action.uses(Inject(my_var=my_var))
def index():
...
Then in index.html
you can use the injected variable:
[[=my_var]]
You can also use Inject
to add variables to the auth.enable line;
in this way auth forms would have access to that variable.
auth.enable(uses=(session, T, db, Inject(TIMEOFFSET=settings.TIMEOFFSET)))
A more complex usage of Inject is for passing python functions to templates. For example if your helper function is called sidebar_menu and it’s inside the libs/helpers.py module of your app, you could use this in controllers.py:
from py4web.utils.factories import Inject
from .libs.helpers import sidebar_menu
@action(...)
@action.uses("index.html", Inject(sidebar_menu=sidebar_menu))
def index(): ....
OR
from py4web.utils.factories import Inject
from .libs import helpers
@action(...)
@action.uses(Inject(**vars(helpers)), "index.html")
def index(): ....
Then you can import the needed code in the index.html template in a clean way:
[[=sidebar_menu]]