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 example

  • named arguments (start with an underscore) interpreted as HTML tag attributes (without the underscore), like _class and _id in the previous example

  • named 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 &lt;world&gt;</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>&lt;strong&gt;hello&lt;/strong&gt;</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))
&lt;script&gt;alert(&quot;unsafe!&quot;)&lt;/script&gt;

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">&lt;click&gt;<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">&lt;hello&gt;<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">&lt;hello&gt;<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">&lt;hello&gt;<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">&lt;hello&gt;<strong>world</strong></h1>

`` HTML``

For tagging an HTML page.

>>> print(HTML(BODY('<hello>', XML('<strong>world</strong>'))))
<html><body>&lt;hello&gt;<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">&lt;hello&gt;<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">&lt;hello&gt;<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">&lt;hello&gt;<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>&lt;hello&gt;</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">&lt;hello&gt;<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">&lt;hello&gt;<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">&lt;hello&gt;<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">&lt;hello&gt;<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>&lt;hello&gt;</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">&lt;hello&gt;<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">&lt;hello&gt;<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>&lt;hello&gt;</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>&lt;hello&gt;<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">&lt;hello&gt;<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>&lt;hello&gt;</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:

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]]