Chapter 5: As visões
As views
O web2py usa o Python para seus models, controllers e views, embora use uma sintaxe Python ligeiramente modificada nas visualizações para permitir código mais legível sem impor nenhuma restrição ao uso adequado do Python.
O objetivo de uma visualização é incorporar o código (Python) em um documento HTML. Em geral, isso coloca alguns problemas: Como o código incorporado deve ser escapado?
- O recuo deve ser baseado em regras Python ou HTML?
web2py usa {{ ... }}
para escapar do código Python incorporado em HTML. A vantagem de usar chaves em vez de colchetes angulares é que ela é transparente para todos os editores HTML comuns. Isso permite que o desenvolvedor use esses editores para criar visualizações web2py. Esses delimitadores podem ser alterados, por exemplo, com
response.delimiters = ('<?', '?>')
Se esta linha estiver em um modelo, ela será aplicada em todos os lugares, se estiver em um controlador apenas para visualizações para as ações do controlador, se dentro de uma ação apenas para a visualização dessa ação.
Como o desenvolvedor está incorporando o código Python ao HTML, o documento deve ser recuado de acordo com as regras HTML e não com as regras do Python. Portanto, permitimos Python sem recuo dentro do {{ ... }}
Tag. Como o Python normalmente usa recuo para delimitar blocos de código, precisamos de uma maneira diferente de delimitá-los; É por isso que a linguagem de modelo web2py faz uso da palavra-chave Python pass
.
Um bloco de código começa com uma linha que termina com dois pontos e termina com uma linha que começa com
pass
. A palavra-chavepass
não é necessário quando o fim do bloco é óbvio do contexto.
Aqui está um exemplo:
{{
if i == 0:
response.write('i is 0')
else:
response.write('i is not 0')
pass
}}
Observe que pass
é uma palavra-chave do Python, não uma palavra-chave web2py. Alguns editores de Python, como o Emacs, usam a palavra-chave pass
para significar a divisão de blocos e usá-lo para re-indentar o código automaticamente.
A linguagem do template web2py faz exatamente o mesmo. Quando encontra algo como:
<html><body>
{{for x in range(10):}}{{=x}}hello<br />{{pass}}
</body></html>
ele traduz em um programa:
response.write("""<html><body>""", escape=False)
for x in range(10):
response.write(x)
response.write("""hello<br />""", escape=False)
response.write("""</body></html>""", escape=False)
response.write
escreve para o response.body
.Quando há um erro em uma visualização web2py, o relatório de erros mostra o código de visualização gerado, não a visualização real, conforme escrita pelo desenvolvedor. Isso ajuda o desenvolvedor a depurar o código realçando o código real que é executado (que é algo que pode ser depurado com um editor de HTML ou com o inspetor DOM do navegador).
Observe também que:
{{=x}}
gera
response.write(x)
Variáveis injetadas no HTML dessa forma são escapadas por padrão. O escape é ignorado se x
é um XML
objeto, mesmo se escape é definido como True
.
Aqui está um exemplo que introduz o H1
ajudante:
{{=H1(i)}}
que é traduzido para:
response.write(H1(i))
após avaliação, o H1
O objeto e seus componentes são recursivamente serializados, escapados e gravados no corpo da resposta. As tags geradas por H1
e HTML interno não são ignorados. Esse mecanismo garante que todo texto --- e somente texto --- exibido na página da web seja sempre evitado, evitando vulnerabilidades XSS. Ao mesmo tempo, o código é simples e fácil de depurar.
O método response.write(obj, escape=True)
leva dois argumentos, o objeto a ser escrito e se ele deve ser escapado (definido como True
por padrão). E se obj
tem um .xml()
método, é chamado eo resultado escrito para o corpo de resposta (o escape
argumento é ignorado). Caso contrário, usa o objeto __str__
método para serializá-lo e, se o argumento de escape for True
, escapa. Todos os objetos auxiliares internos ( H1
no exemplo) são objetos que sabem como serializar-se através do .xml()
método.
Tudo isso é feito de forma transparente. Você nunca precisa (e nunca deve) ligar para o response.write
método explicitamente.
Sintaxe básica
A linguagem de modelos web2py suporta todas as estruturas de controle do Python. Aqui nós fornecemos alguns exemplos de cada um deles. Eles podem ser aninhados de acordo com a prática usual de programação.
for...in
Nos modelos, você pode fazer um loop sobre qualquer objeto iterável:
{{items = ['a', 'b', 'c']}}
<ul>
{{for item in items:}}<li>{{=item}}</li>{{pass}}
</ul>
que produz:
<ul>
<li>a</li>
<li>b</li>
<li>c</li>
</ul>
Aqui item
é qualquer objeto iterável, como uma lista Python, uma tupla Python ou um objeto Rows, ou qualquer objeto que seja implementado como um iterador. Os elementos exibidos são primeiro serializados e escapados.
while
Você pode criar um loop usando a palavra-chave while:
{{k = 3}}
<ul>
{{while k > 0:}}<li>{{=k}}{{k = k - 1}}</li>{{pass}}
</ul>
que produz:
<ul>
<li>3</li>
<li>2</li>
<li>1</li>
</ul>
if...elif...else
if elif else
Você pode usar cláusulas condicionais:
{{
import random
k = random.randint(0, 100)
}}
<h2>
{{=k}}
{{if k % 2:}}is odd{{else:}}is even{{pass}}
</h2>
que produz:
<h2>
45 is odd
</h2>
Desde que é óbvio que else
fecha o primeiro if
bloco, não há necessidade de pass
declaração, e usando um seria incorreto. No entanto, você deve fechar explicitamente else
bloquear com um pass
.
Lembre-se que em Python "else if" está escrito elif
como no exemplo a seguir:
{{
import random
k = random.randint(0, 100)
}}
<h2>
{{=k}}
{{if k % 4 == 0:}}is divisible by 4
{{elif k % 2 == 0:}}is even
{{else:}}is odd
{{pass}}
</h2>
Produz:
<h2>
64 is divisible by 4
</h2>
try...except...else...finally
try except else finally
Também é possível usar try...except
declarações em pontos de vista com uma ressalva. Considere o seguinte exemplo:
{{try:}}
Hello {{= 1 / 0}}
{{except:}}
division by zero
{{else:}}
no division by zero
{{finally}}
<br />
{{pass}}
Produzirá a seguinte saída:
Hello
division by zero
<br />
Este exemplo ilustra que toda a saída gerada antes de ocorrer uma exceção é renderizada (incluindo a saída que precedeu a exceção) dentro do bloco try. "Olá" é escrito porque precede a exceção.
def...return
def return
A linguagem de template web2py permite ao desenvolvedor definir e implementar funções que podem retornar qualquer objeto Python ou uma string text/html. Aqui nós consideramos dois exemplos:
{{def itemize1(link): return LI(A(link, _href="http://" + link))}}
<ul>
{{=itemize1('www.google.com')}}
</ul>
produz a seguinte saída:
<ul>
<li><a href="http:/www.google.com">www.google.com</a></li>
</ul>
A função itemize1
retorna um objeto auxiliar que é inserido no local onde a função é chamada.
Considere agora o seguinte código:
{{def itemize2(link):}}
<li><a href="http://{{=link}}">{{=link}}</a></li>
{{return}}
<ul>
{{itemize2('www.google.com')}}
</ul>
Produz exatamente a mesma saída acima. Neste caso, a função itemize2
representa um pedaço de HTML que vai substituir a tag web2py onde a função é chamada. Observe que não há '=' na frente da chamada para itemize2
, uma vez que a função não retorna o texto, mas o grava diretamente na resposta.
Há uma ressalva: as funções definidas dentro de uma visualização devem terminar com uma instrução de retorno ou a indentação automática falhará.
Ajudantes HTML
Considere o seguinte código em uma visão:
{{=DIV('this', 'is', 'a', 'test', _id='123', _class='myclass')}}
é processado como:
<div id="123" class="myclass">thisisatest</div>
DIV
é uma classe auxiliar, isto é, algo que pode ser usado para construir HTML programaticamente. Corresponde ao HTML <div>
tag.Os argumentos posicionais são interpretados como objetos contidos entre as tags de abertura e fechamento. Os argumentos nomeados que começam com um sublinhado são interpretados como atributos de marca HTML (sem o sublinhado). Alguns ajudantes também nomearam argumentos que não iniciam com sublinhado; esses argumentos são específicos de tags.
Em vez de um conjunto de argumentos sem nome, um auxiliar também pode obter uma única lista ou tupla como seu conjunto de componentes usando *
notação e pode ter um único dicionário como o seu conjunto de atributos usando o **
, por exemplo:
{{
contents = ['this', 'is', 'a', 'test']
attributes = {'_id':'123', '_class':'myclass'}
=DIV(*contents, **attributes)
}}
(produz o mesmo resultado de antes).
O seguinte conjunto de ajudantes:
A
, ASSIGNJS
, B
, BEAUTIFY
, BODY
, BR
, CAT
, CENTER
, CODE
, COL
, COLGROUP
, DIV
, EM
, EMBED
, FIELDSET
, FORM
, H1
, H2
, H3
, H4
, H5
, H6
, HEAD
, HR
, HTML
, I
, IFRAME
, IMG
, INPUT
, LABEL
, LEGEND
, LI
, LINK
, MARKMIN
, MENU
, META
, OBJECT
, ON
, OL
, OPTGROUP
, OPTION
, P
, PRE
, SCRIPT
, SELECT
, SPAN
, STYLE
, TABLE
, TAG
, TBODY
, TD
, TEXTAREA
, TFOOT
, TH
, THEAD
, TITLE
, TR
, TT
, UL
, URL
, XHTML
, XML
, embed64
, xmlescape
pode ser usado para construir expressões complexas que podem ser serializadas para XML [xml-w] [xml-o] . Por exemplo:
{{=DIV(B(I("hello ", "<world>")), _class="myclass")}}
é processado:
<div class="myclass"><b><i>hello <world></i></b></div>
Os assistentes também podem ser serializados em strings, de forma equivalente, com o __str__
e a xml
métodos:
>>> print str(DIV("hello world"))
<div>hello world</div>
>>> print DIV("hello world").xml()
<div>hello world</div>
O mecanismo de ajuda no web2py é mais que um sistema para gerar HTML sem concatenar strings. Ele fornece uma representação do lado do servidor do Document Object Model (DOM).
Os componentes dos ajudantes podem ser referenciados por meio de sua posição e os auxiliares atuam como listas em relação aos seus componentes:
>>> a = DIV(SPAN('a', 'b'), 'c')
>>> print a
<div><span>ab</span>c</div>
>>> del a[1]
>>> a.append(B('x'))
>>> a[0][0] = 'y'
>>> print a
<div><span>yb</span><b>x</b></div>
Atributos de ajudantes podem ser referenciados pelo nome e os auxiliares atuam como dicionários em 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 que o conjunto completo de componentes pode ser acessado através de uma lista chamada a.components
, e o conjunto completo de atributos pode ser acessado através de um dicionário chamado a.attributes
. Assim, a[i]
é equivalente a a.components[i]
quando i
é um inteiro e a[s]
é equivalente a a.attributes[s]
quando s
é uma string.
Observe que os atributos auxiliares são passados como argumentos de palavra-chave para o auxiliar. Em alguns casos, no entanto, os 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 palavras-chave. Por exemplo:
DIV('text', _data-role='collapsible')
não funcionará porque "_data-role" inclui um hífen, o que produzirá um erro de sintaxe Python.
Em tais casos, você tem algumas opções. Você pode usar o data
argumento (desta vez sem um sublinhado à esquerda) para passar um dicionário de atributos relacionados sem o hífen inicial, e a saída terá as combinações desejadas, por ex.
>>> print DIV('text', data={'role': 'collapsible'})
<div data-role="collapsible">text</div>
ou você pode passar os atributos como um dicionário e fazer uso do Python **
notação de argumentos de função, que mapeia um dicionário de pares (chave: valor) em um conjunto de argumentos de palavras-chave:
>>> print DIV('text', **{'_data-role': 'collapsible'})
<div data-role="collapsible">text</div>
Observe que entradas mais elaboradas introduzirão entidades de caracteres HTML, mas funcionarão, por exemplo,
>>> print DIV('text', data={'options':'{"mode":"calbox", "useNewStyle":true}'})
<div data-options="{"mode":"calbox", "useNewStyle":true}">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>
XML
XML
é um objeto usado para encapsular texto que não deve ser escapado. O texto pode ou não conter um XML válido. Por exemplo, ele pode conter JavaScript.O texto neste exemplo é escapado:
>>> print DIV("<b>hello</b>")
<b>hello</b>
usando XML
você pode evitar o escape:
>>> print DIV(XML("<b>hello</b>"))
<b>hello</b>
Às vezes, você deseja renderizar HTML armazenado em uma variável, mas o HTML pode conter tags não seguras, como scripts:
>>> print XML('<script>alert("unsafe!")</script>')
<script>alert("unsafe!")</script>
Uma entrada executável não escapada como essa (por exemplo, inserida no corpo de um comentário em um blog) não é segura, porque pode ser usada para gerar ataques de Cross Site Scripting (XSS) contra outros visitantes da página.
O web2py XML
O ajudante pode higienizar nosso texto para evitar injeções e escapar de todas as tags, exceto aquelas que você permite explicitamente. Aqui está um exemplo:
>>> print XML('<script>alert("unsafe!")</script>', sanitize=True)
<script>alert("unsafe!")</script>
o XML
construtores, por padrão, consideram o conteúdo de algumas tags e alguns de seus atributos seguros. Você pode substituir os padrões usando o opcional permitted_tags
e allowed_attributes
argumentos. Aqui estão os valores padrão dos argumentos opcionais do XML
ajudante.
XML(text, sanitize=False,
permitted_tags=['a', 'b', 'blockquote', 'br/', 'i', 'li',
'ol', 'ul', 'p', 'cite', 'code', 'pre', 'img/'],
allowed_attributes={'a':['href', 'title'],
'img':['src', 'alt'], 'blockquote':['type']})
Ajudantes embutidos
A
Este ajudante é usado para construir links.
>>> print A('<click>', XML('<b>me</b>'),
_href='http://www.web2py.com')
<a href='http://www.web2py.com'><click><b>me/b></a>
Ao invés de _href
você pode passar o URL usando o callback
argumento. Por exemplo, em uma visão:
{{=A('click me', callback=URL('myaction'))}}
e o efeito de pressionar o link será uma chamada ajax para "myaction" em vez de um redirecionamento. Nesse caso, opcionalmente, você pode especificar mais dois argumentos: target
e delete
:
{{=A('click me', callback=URL('myaction'), target="t")}}
<div id="t"><div>
e a resposta do callback do ajax será armazenada no DIV com id igual a "t".
<div id="b">{{=A('click me', callback=URL('myaction'), delete='div#b")}}</div>
b "será excluído. Nesse caso, o botão será excluído.
Uma aplicação típica é:
{{=A('click me', callback=URL('myaction'), delete='tr")}}
em uma tabela. Pressionar o botão executará o retorno de chamada e excluirá a linha da tabela.
callback
e delete
pode ser combinado.
O ajudante A leva um argumento especial chamado cid
. Funciona da seguinte maneira:
{{=A('linked page', _href='http://example.com', cid='myid')}}
<div id="myid"></div>
e um clique no link faz com que o conteúdo seja carregado no div. Isso é semelhante, mas é mais poderoso do que a sintaxe acima, pois foi projetado para atualizar os componentes da página. Discutimos as aplicações de cid
em mais detalhes em Capítulo 12 , no contexto de componentes.
Esses recursos do ajax requerem jQuery e "static/js/web2py_ajax.js", que são incluídos automaticamente colocando {{include 'web2py_ajax.html'}}
na cabeça do layout. "views/web2py_ajax.html" define algumas variáveis baseadas em request
e inclui todos os arquivos js e css necessários.
ASSIGNJS
ASSIGNJS permite que um valor do lado do servidor seja usado como um lado do cliente valor de javascript.
Por exemplo, se em um controlador você escreve
return dict(stra='abcd', obj=alist)
e em uma visão escrever
<script>
{{=ASSIGNJS(o=obj)}}
...
Então a variável javascript o terá o valor passado em obj, qual é alist.
Um outro exemplo é mostrado abaixo sob Javascript In Views .
B
Este ajudante faz seu conteúdo em negrito.
>>> print B('<hello>', XML('<i>world</i>'), _class='test', _id=0)
<b id="0" class="test"><hello><i>world</i></b>
BODY
Este ajudante faz o corpo de uma página.
>>> print BODY('<hello>', XML('<b>world</b>'), _bgcolor='red')
<body bgcolor="red"><hello><b>world</b></body>
BR
Este ajudante cria uma quebra de linha.
>>> print BR()
<br />
Observe que os ajudantes podem ser repetidos usando o operador de multiplicação:
>>> print BR()*5
<br /><br /><br /><br /><br />
CAT
Este ajudante concatena outros ajudantes, da mesma forma que TAG [\ ''].
>>> print CAT('Here is a ', A('link', _href=URL()), ', and here is some ', B('bold text'), '.')
Here is a <a href="/app/default/index">link</a>, and here is some <b>bold text</b>.
CENTER
Este ajudante centraliza seu conteúdo.
>>> print CENTER('<hello>', XML('<b>world</b>'),
>>> _class='test', _id=0)
<center id="0" class="test"><hello><b>world</b></center>
CODE
Esse auxiliar executa realce de sintaxe para códigos Python, C, C ++, HTML e web2py e é preferível a PRE
para listagens de código. CODE
também tem a capacidade de criar links para a documentação da API web2py.
Aqui está um exemplo de destaque de seções do código Python.
>>> print CODE('print "hello"', language='python').xml()
<table><tr valign="top"><td style="width:40px; text-align: right;"><pre style="
font-size: 11px;
font-family: Bitstream Vera Sans Mono,monospace;
background-color: transparent;
margin: 0;
padding: 5px;
border: none;
background-color: #E0E0E0;
color: #A0A0A0;
">1.</pre></td><td><pre style="
font-size: 11px;
font-family: Bitstream Vera Sans Mono,monospace;
background-color: transparent;
margin: 0;
padding: 5px;
border: none;
overflow: auto;
"><span style="color:#185369; font-weight: bold">print </span>
<span style="color: #FF9966">"hello"</span></pre></td></tr>
</table>
Aqui está um exemplo semelhante para HTML
>>> print CODE(
>>> '<html><body>{{=request.env.remote_add}}</body></html>',
>>> language='html')
<table>...<code>...
<html><body>{{=request.env.remote_add}}</body></html>
...</code>...</table>
Estes são os argumentos padrão para o CODE
ajudante:
CODE("print 'hello world'", language='python', link=None, counter=1, styles={})
Valores suportados para o language
Os argumentos são "python", "html_plain", "c", "cpp", "web2py" e "html". A linguagem "html" interpreta as tags {{e}} como código "web2py", enquanto "html_plain" não.
Se um link
value é especificado, por exemplo, "/ examples/global/vars /", as referências da API web2py no código são vinculadas à documentação na URL do link. Por exemplo, "solicitação" seria vinculada a "/ examples/global/vars/request". No exemplo acima, o URL do link é manipulado pela ação "vars" no controlador "global.py" que é distribuído como parte do aplicativo web2py "examples".
o counter
argumento é usado para numeração de linhas. Pode ser definido para qualquer um dos três valores diferentes. Pode ser None
para nenhum número de linha, um valor numérico especificando o número inicial ou uma string. Se o contador estiver configurado para uma string, ele será interpretado como um prompt e não haverá números de linha.
o styles
argumento é um pouco complicado. Se você olhar o HTML gerado acima, ele contém uma tabela com duas colunas e cada coluna tem seu próprio estilo declarado inline usando CSS. o styles
atributos permite que você substitua esses dois estilos CSS. Por exemplo:
{{=CODE(..., styles={'CODE':'margin: 0;padding: 5px;border: none;'})}}
o styles
atributo deve ser um dicionário e permite duas chaves possíveis: CODE
para o estilo do código real e LINENUMBERS
para o estilo da coluna da esquerda, que contém os números de linha. Lembre-se de que esses estilos substituem completamente os estilos padrão e não são simplesmente adicionados a eles.
COL
>>> print COL('a', 'b')
<col>ab</col>
COLGROUP
>>> print COLGROUP('a', 'b')
<colgroup>ab</colgroup>
DIV
Todos os ajudantes, além de XML
são derivados de DIV
e herdar seus métodos básicos.
>>> print DIV('<hello>', XML('<b>world</b>'), _class='test', _id=0)
<div id="0" class="test"><hello><b>world</b></div>
EM
Enfatiza seu conteúdo.
>>> print EM('<hello>', XML('<b>world</b>'), _class='test', _id=0)
<em id="0" class="test"><hello><b>world</b></em>
FIELDSET
Isso é usado para criar um campo de entrada junto com seu rótulo.
>>> print FIELDSET('Height:', INPUT(_name='height'), _class='test')
<fieldset class="test">Height:<input name="height" /></fieldset>
FORM
Este é um dos ajudantes mais importantes. Na sua forma simples, faz apenas um <form>...</form>
mas porque os ajudantes são objetos e têm conhecimento do que eles contêm, eles podem processar formulários enviados (por exemplo, executar a validação dos campos). Isso será discutido em detalhes no Capítulo 7.
>>> print FORM(INPUT(_type='submit'), _action='', _method='post')
<form enctype="multipart/form-data" action="" method="post">
<input type="submit" /></form>
O "enctype" é "multipart/form-data" por padrão.
O construtor de um FORM
, e de SQLFORM
, também pode ter um argumento especial chamado hidden
. Quando um dicionário é passado como hidden
, seus itens são traduzidos em campos INPUT "ocultos". Por exemplo:
>>> print FORM(hidden=dict(a='b'))
<form enctype="multipart/form-data" action="" method="post">
<input value="b" type="hidden" name="a" /></form>
H1
, H2
, H3
, H4
, H5
, H6
Esses ajudantes são para cabeçalhos e subtítulos de parágrafos:
>>> print H1('<hello>', XML('<b>world</b>'), _class='test', _id=0)
<h1 id="0" class="test"><hello><b>world</b></h1>
HEAD
Para marcar o HEAD de uma página HTML.
>>> print HEAD(TITLE('<hello>', XML('<b>world</b>')))
<head><title><hello><b>world</b></title></head>
HTML
HTML XHTML
Esse ajudante é um pouco diferente. Além de fazer o <html>
Tag, ele preenche a tag com uma string doctype [xhtml-w,xhtml-o,xhtml-school] .
>>> print HTML(BODY('<hello>', XML('<b>world</b>')))
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html><body><hello><b>world</b></body></html>
O auxiliar de HTML também usa alguns argumentos opcionais adicionais que possuem o seguinte padrão:
HTML(..., lang='en', doctype='transitional')
em que doctype pode ser 'strict', 'transitional', 'frameset', 'html5' ou uma string completa do tipo doctype.
XHTML
O XHTML é semelhante ao HTML, mas cria um tipo de documento XHTML.
XHTML(..., lang='en', doctype='transitional', xmlns='http://www.w3.org/1999/xhtml')
em que doctype pode ser 'strict', 'transitional', 'frameset' ou uma string completa do tipo doctype.
HR
Este ajudante cria uma linha horizontal em uma página HTML
>>> print HR()
<hr />
I
Este ajudante faz seu conteúdo em itálico.
>>> print I('<hello>', XML('<b>world</b>'), _class='test', _id=0)
<i id="0" class="test"><hello><b>world</b></i>
IFRAME
Este ajudante inclui outra página da web na página atual. A URL da outra página é especificada pelo atributo "_src".
>>> print IFRAME(_src='http://www.web2py.com')
<iframe src="http://www.web2py.com"></iframe>
IMG
Pode ser usado para incorporar imagens em HTML:
>>> IMG(_src='http://example.com/image.png', _alt='test')
<img src="http://example.com/image.ong" alt="rest" />
Aqui está uma combinação de ajudantes A, IMG e URL para incluir uma imagem estática com um link:
>>> A(IMG(_src=URL('static', 'logo.png'), _alt="My Logo"),
_href=URL('default', 'index'))
<a href="/myapp/default/index">
<img src="/myapp/static/logo.png" alt="My Logo" />
</a>
INPUT
Cria um <input.../>
tag. Uma tag de entrada não pode conter outras tags e é fechada por />
ao invés de >
. A tag de entrada possui um atributo opcional _type
que pode ser definido como "texto" (o padrão), "enviar", "caixa de seleção" ou "rádio".
>>> print INPUT(_name='test', _value='a')
<input value="a" name="test" />
Também é necessário um argumento especial opcional chamado "value", distinto de "_value". O último define o valor padrão para o campo de entrada; o primeiro define seu valor atual. Para uma entrada do tipo "texto", o primeiro substitui o último:
>>> print INPUT(_name='test', _value='a', value='b')
<input value="b" name="test" />
Para botões de rádio, INPUT
seletivamente define o atributo "checked":
>>> for v in ['a', 'b', 'c']:
>>> print INPUT(_type='radio', _name='test', _value=v, value='b'), v
<input value="a" type="radio" name="test" /> a
<input value="b" type="radio" checked="checked" name="test" /> b
<input value="c" type="radio" name="test" /> c
e da mesma forma para caixas de seleção:
>>> print INPUT(_type='checkbox', _name='test', _value='a', value=True)
<input value="a" type="checkbox" checked="checked" name="test" />
>>> print INPUT(_type='checkbox', _name='test', _value='a', value=False)
<input value="a" type="checkbox" name="test" />
LABEL
É usado para criar uma tag LABEL para um campo INPUT.
>>> print LABEL('<hello>', XML('<b>world</b>'), _class='test', _id=0)
<label id="0" class="test"><hello><b>world</b></label>
LEGEND
Ele é usado para criar uma legenda para um campo em um formulário.
>>> print LEGEND('Name', _for='myfield')
<legend for="myfield">Name</legend>
LI
Ele faz um item de lista e deve estar contido em um UL
ou OL
tag.
>>> print LI('<hello>', XML('<b>world</b>'), _class='test', _id=0)
<li id="0" class="test"><hello><b>world</b></li>
META
Para ser usado para construção META
tags no HTML
cabeça. Por exemplo:
>>> print META(_name='security', _content='high')
<meta name="security" content="high" />
MARKMIN
Implementa a sintaxe do wiki markmin. Converte o texto de entrada em html de saída de acordo com as regras markmin descritas no exemplo abaixo:
>>> print MARKMIN("this is **bold** or ''italic'' and this [[a link http://web2py.com]]")
<p>this is <b>bold</b> or <i>italic</i> and
this <a href="http://web2py.com">a link</a></p>
A sintaxe markmin é descrita neste arquivo que acompanha o web2py:
http://127.0.0.1:8000/examples/static/markmin.html
Você pode usar o markmin para gerar documentos HTML, LaTeX e PDF:
m = "Hello **world** [[link http://web2py.com]]"
from gluon.contrib.markmin.markmin2html import markmin2html
print markmin2html(m)
from gluon.contrib.markmin.markmin2latex import markmin2latex
print markmin2latex(m)
from gluon.contrib.markmin.markmin2pdf import markmin2pdf
print markmin2pdf(m) # requires pdflatex
(a MARKMIN
ajudante é um atalho para markmin2html
)
Aqui está um primer de sintaxe básico:
FONTE | SAÍDA |
# title | título |
## section | seção |
### subsection | subseção |
**bold** | negrito |
''italic'' | itálico |
``verbatim`` | verbatim |
http://google.com | http://google.com |
http://... | <a href="http://...">http:...</a> |
http://...png | <img src="http://...png" /> |
http://...mp3 | <audio src="http://...mp3"></audio> |
http://...mp4 | <video src="http://...mp4"></video> |
qr:http://... | <a href="http://..."><img src="qr code"/></a> |
embed:http://... | <iframe src="http://..."></iframe> |
[[click me #myanchor]] | click me |
[[myanchor]] | Criando uma âncora para um link |
$ $\int_a^b sin(x)dx$ $ | |
-------------------------------------------------- - | |
##### Links MARKMIN | |
Os links assumem este formato: [[link display text <link>]] | |
<link> pode ser uma âncora, e. #myanchor | |
ou um URI, por exemplo http://www.web2py.com | |
ou uma referência relativa, p. [[See Chapter 8 ../08]] ou [[See Chapter 8 ../08#myanchor]] | |
Simplesmente incluir um link para uma imagem, um vídeo ou um arquivo de áudio sem marcação faz com que a imagem, vídeo ou arquivo de áudio correspondente sejam incluídos automaticamente (para áudio e vídeo, ele usa as tags <audio> e <video>). | |
Adicionando um link com o qr: prefixo como | |
| |
resulta no código QR correspondente sendo incorporado e vinculando a referida URL. | |
Adicionando um link com o embed: prefixo como | |
| |
resulta na página sendo incorporada, neste caso, um vídeo do youtube é incorporado. | |
As imagens também podem ser incorporadas com a seguinte sintaxe: | |
| |
##### MARKMIN listas e tabelas | |
Listas não ordenadas com: | |
| |
Listas ordenadas com: | |
| |
e tabelas com: | |
| |
##### estendendo MARKMIN | |
A sintaxe MARKMIN também suporta blockquotes, tags de áudio e vídeo HTML5, alinhamento de imagens, CSS personalizado e pode ser estendido: | |
MARKMIN("``abab``:custom", extra=dict(custom=lambda text: text.replace('a', 'c'))
| |
gera | |
'cbcb'
| |
Blocos personalizados são delimitados por ``...``:<key> e eles são renderizados pela função passada como valor para a chave correspondente no argumento de dicionário extra de MARKMIN. Lembre-se de que a função pode precisar escapar da saída para evitar o XSS. | |
#### OBJECT | |
Usado para incorporar objetos (por exemplo, um flash player) no HTML. | |
OBJECT | |
>>> print OBJECT('<hello>', XML('<b>world</b>'),
>>> _src='http://www.web2py.com')
<object src="http://www.web2py.com"><hello><b>world</b></object>
| |
#### OL | |
Significa a lista ordenada. A lista deve conter tags do LI. OL argumentos que não são LI objetos são automaticamente incluídos <li>...</li> Tag. | |
OL | |
>>> print OL('<hello>', XML('<b>world</b>'), _class='test', _id=0)
<ol id="0" class="test"><li><hello></li><li><b>world</b></li></ol>
| |
#### ON | |
Isto está aqui para compatibilidade com versões anteriores e é simplesmente um alias para True . É usado exclusivamente para caixas de seleção e obsoleto desde True é mais pitonico. | |
ON | |
>>> print INPUT(_type='checkbox', _name='test', _checked=ON)
<input checked="checked" type="checkbox" name="test" />
| |
#### OPTGROUP | |
Permite agrupar várias opções em um SELECT e é útil personalizar os campos usando CSS. | |
OPTGROUP | |
>>> print SELECT('a', OPTGROUP('b', 'c'))
<select>
<option value="a">a</option>
<optgroup>
<option value="b">b</option>
<option value="c">c</option>
</optgroup>
</select>
| |
#### OPTION | |
Isso só deve ser usado como parte de uma combinação SELECT/OPTION. | |
OPTION | |
>>> print OPTION('<hello>', XML('<b>world</b>'), _value='a')
<option value="a"><hello><b>world</b></option>
| |
Como no caso de INPUT , web2py faz uma distinção entre "_value" (o valor da OPTION) e "value" (o valor atual da seleção de inclusão). Se eles são iguais, a opção é "selecionada". | |
selected | |
>>> print SELECT('a', 'b', value='b'):
<select>
<option value="a">a</option>
<option value="b" selected="selected">b</option>
</select>
| |
#### P | |
P | |
Isto é para marcar um parágrafo. | |
>>> print P('<hello>', XML('<b>world</b>'), _class='test', _id=0)
<p id="0" class="test"><hello><b>world</b></p>
| |
#### PRE | |
PRE | |
Gera um <pre>...</pre> tag para exibir o texto pré-formatado. o CODE O auxiliar é geralmente preferível para listagens de código. | |
>>> print PRE('<hello>', XML('<b>world</b>'), _class='test', _id=0)
<pre id="0" class="test"><hello><b>world</b></pre>
| |
#### SCRIPT | |
SCRIPT | |
Isso é incluir ou vincular um script, como JavaScript. O conteúdo entre as tags é renderizado como um comentário HTML, para o benefício de navegadores realmente antigos. | |
>>> print SCRIPT('alert("hello world");', _type='text/javascript')
<script type="text/javascript"><!--
alert("hello world");
//--></script>
| |
#### SELECT | |
SELECT | |
Faz um <select>...</select> tag. Isso é usado com o OPTION ajudante. Essa SELECT argumentos que não são OPTION objetos são automaticamente convertidos em opções. | |
>>> print SELECT('<hello>', XML('<b>world</b>'), _class='test', _id=0)
<select id="0" class="test">
<option value="<hello>"><hello></option>
<option value="<b>world</b>"><b>world</b></option>
</select>
| |
#### SPAN | |
SPAN | |
Igual a DIV mas usado para marcar conteúdo inline (em vez de bloquear). | |
>>> print SPAN('<hello>', XML('<b>world</b>'), _class='test', _id=0)
<span id="0" class="test"><hello><b>world</b></span>
| |
#### STYLE | |
STYLE | |
Semelhante ao script, mas usado para incluir ou vincular o código CSS. | |
Aqui o CSS está incluído: | |
>>> print STYLE(XML('body {color: white}'))
<style><!--
body { color: white }
//--></style>
| |
e aqui está ligado: | |
>>> print STYLE(_src='style.css')
<style src="style.css"><!--
//--></style>
| |
#### TABLE , TR , TD | |
TABLE TR TD | |
Essas tags (junto com o opcional THEAD , TBODY e TFOOTER helpers) são usados para construir tabelas 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 espera TD conteúdo; argumentos que não são TD objetos são convertidos automaticamente. | |
>>> print TABLE(TR('a', 'b'), TR('c', 'd'))
<table><tr><td>a</td><td>b</td></tr><tr><td>c</td><td>d</td></tr></table>
| |
É fácil converter um array Python em uma tabela HTML usando o Python * notação de argumentos de função, que mapeia elementos de lista para argumentos de função posicional. | |
Aqui, faremos isso linha por linha: | |
>>> table = [['a', 'b'], ['c', 'd']]
>>> print TABLE(TR(*table[0]), TR(*table[1]))
<table><tr><td>a</td><td>b</td></tr><tr><td>c</td><td>d</td></tr></table>
| |
Aqui nós fazemos todas as linhas de uma só vez: | |
>>> table = [['a', 'b'], ['c', 'd']]
>>> print TABLE(*[TR(*rows) for rows in table])
<table><tr><td>a</td><td>b</td></tr><tr><td>c</td><td>d</td></tr></table>
| |
#### TBODY | |
TBODY | |
Isso é usado para marcar linhas contidas no corpo da tabela, em oposição a linhas de cabeçalho ou rodapé. É opcional. | |
>>> print TBODY(TR('<hello>'), _class='test', _id=0)
<tbody id="0" class="test"><tr><td><hello></td></tr></tbody>
| |
#### TEXTAREA | |
TEXTAREA | |
Este ajudante faz uma <textarea>...</textarea> tag. | |
>>> print TEXTAREA('<hello>', XML('<b>world</b>'), _class='test')
<textarea class="test" cols="40" rows="10"><hello><b>world</b></textarea>
| |
A única ressalva é que seu "valor" opcional substitui seu conteúdo (HTML interno) | |
>>> print TEXTAREA(value="<hello world>", _class="test")
<textarea class="test" cols="40" rows="10"><hello world></textarea>
| |
#### TFOOT | |
TFOOT | |
Isso é usado para marcar as linhas de rodapé da tabela. | |
>>> print TFOOT(TR(TD('<hello>')), _class='test', _id=0)
<tfoot id="0" class="test"><tr><td><hello></td></tr></tfoot>
| |
#### TH | |
TH | |
Isso é usado em vez de TD nos cabeçalhos de tabela. | |
>>> print TH('<hello>', XML('<b>world</b>'), _class='test', _id=0)
<th id="0" class="test"><hello><b>world</b></th>
| |
#### THEAD | |
THEAD | |
Isso é usado para marcar as linhas do cabeçalho da tabela. | |
>>> print THEAD(TR(TH('<hello>')), _class='test', _id=0)
<thead id="0" class="test"><tr><th><hello></th></tr></thead>
| |
#### TITLE | |
TITLE | |
Isso é usado para marcar o título de uma página em um cabeçalho HTML. | |
>>> print TITLE('<hello>', XML('<b>world</b>'))
<title><hello><b>world</b></title>
| |
#### TR | |
TR | |
Tags uma linha da tabela. Deve ser renderizado dentro de uma tabela e conter <td>...</td> Tag. TR argumentos que não são TD objetos serão convertidos automaticamente. | |
>>> print TR('<hello>', XML('<b>world</b>'), _class='test', _id=0)
<tr id="0" class="test"><td><hello></td><td><b>world</b></td></tr>
| |
#### TT | |
TT | |
Tags texto como texto de máquina de escrever (monoespaçada). | |
>>> print TT('<hello>', XML('<b>world</b>'), _class='test', _id=0)
<tt id="0" class="test"><hello><b>world</b></tt>
| |
#### UL | |
Significa uma lista não ordenada e deve conter itens LI. Se seu conteúdo não estiver marcado como LI, a UL o fará automaticamente. | |
UL | |
>>> print UL('<hello>', XML('<b>world</b>'), _class='test', _id=0)
<ul id="0" class="test"><li><hello></li><li><b>world</b></li></ul>
| |
#### URL | |
O auxiliar de URL está documentado em Capítulo 4 URL | |
#### embed64 | |
embed64(filename=None, file=None, data=None, extension='image/gif') codifica os dados fornecidos (binários) para base64. | |
filename: se fornecido, abre e lê este arquivo no modo 'rb'. | |
file: se fornecido, lê este arquivo. | |
dados: se fornecidos, usam os dados fornecidos. | |
embed64 | |
#### xmlescape | |
xmlescape(data, quote=True) retorna uma string de escape dos dados fornecidos. | |
xmlescape | |
>>> print xmlescape('<hello>')
<hello>
| |
### Ajudantes personalizados | |
#### TAG | |
TAG | |
Às vezes você precisa gerar tags XML personalizadas. o web2py fornece TAG , um gerador de tag universal. | |
{{=TAG.name('a', 'b', _c='d')}}
| |
gera o seguinte XML | |
<name c="d">ab</name>
| |
Argumentos "a", "b" e "d" são automaticamente escapados; use o XML ajudante para suprimir esse comportamento. Usando TAG você pode gerar tags HTML/XML que ainda não foram fornecidas pela API. Os TAGs podem ser aninhados e serializados com str(). | |
Uma sintaxe equivalente é: | |
{{=TAG['name']('a', 'b', c='d')}}
| |
Se o objeto TAG for criado com um nome vazio, ele poderá ser usado para concatenar várias strings e auxiliares HTML juntos sem inseri-los em uma tag circundante, mas esse uso será preterido. Use o CAT ajudante em vez disso. | |
Tags de fechamento automático podem ser geradas com o auxiliar TAG. O nome da tag deve terminar com "/". | |
{{=TAG['link/'](_href='http://web2py.com')}}
| |
gera o seguinte XML: | |
<link ref="http://web2py.com"/>
| |
Notar que TAG é um objeto e TAG.name ou TAG['name'] é uma função que retorna uma classe auxiliar temporária. | |
#### MENU | |
MENU | |
O auxiliar do MENU pega uma lista de listas ou de tuplas da forma de response.menu (como descrito no Capítulo 4) e gera uma estrutura de árvore usando listas não ordenadas que representam o menu. Por exemplo: | |
>>> print MENU([['One', False, 'link1'], ['Two', False, 'link2']])
<ul class="web2py-menu web2py-menu-vertical">
<li><a href="link1">One</a></li>
<li><a href="link2">Two</a></li>
</ul>
| |
O primeiro item em cada lista/tupla é o texto a ser exibido para o item de menu fornecido.
O segundo item em cada lista/tupla é um booleano indicando se esse item de menu específico está ativo (isto é, o item atualmente selecionado). Quando definido como True, o auxiliar MENU () adicionará um "web2py-menu-active" class para o <li> para esse item (você pode alterar o nome dessa classe através do argumento "li_active" para MENU ()). Outra maneira de especificar o url ativo é passando diretamente para MENU () através do argumento "active_url".
O terceiro item em cada lista/tupla pode ser um auxiliar HTML (que pode incluir ajudantes aninhados), e o MENU
ajudante irá simplesmente processar esse ajudante, em vez de criar seu próprio <a>
tag.
Cada item de menu pode ter um quarto argumento que é um submenu aninhado (e assim por diante recursivamente):
>>> print MENU([['One', False, 'link1', [['Two', False, 'link2']]]])
<ul class="web2py-menu web2py-menu-vertical">
<li class="web2py-menu-expand">
<a href="link1">One</a>
<ul class="web2py-menu-vertical">
<li><a href="link2">Two</a></li>
</ul>
</li>
</ul>
Um item de menu também pode ter um 5º elemento opcional, que é um booleano. Quando falso, o item de menu é ignorado pelo auxiliar do MENU.
O auxiliar do MENU usa os seguintes argumentos opcionais:
_class
: o padrão é "web2py-menu web2py-menu-vertical" e define a classe dos elementos UL externos.ul_class
: o padrão é "web2py-menu-vertical" e define a classe dos elementos UL internos.li_class
: o padrão é "web2py-menu-expand" e define a classe dos elementos internos do LI.li_first
: permite adicionar uma classe ao primeiro elemento da lista.li_last
: permite adicionar uma classe ao último elemento da lista.
MENU
leva um argumento opcional mobile
. Quando definido para True
em vez de construir uma recursiva UL
estrutura de menu retorna um SELECT
dropdown com todas as opções de menu e um onchange
atributo que redireciona para a página correspondente à opção selecionada. Isto é projetado uma representação de menu alternativa que aumenta a usabilidade em pequenos dispositivos móveis, como telefones.
Normalmente, o menu é usado em um layout com a seguinte sintaxe:
{{=MENU(response.menu, mobile=request.user_agent().is_mobile)}}
Dessa forma, um dispositivo móvel é detectado automaticamente e o menu é renderizado de acordo.
BEAUTIFY
BEAUTIFY
é usado para construir representações em HTML de objetos compostos, incluindo listas, tuplas e dicionários:
{{=BEAUTIFY({"a": ["hello", XML("world")], "b": (1, 2)})}}
BEAUTIFY
retorna um objeto semelhante a XML serializável para XML, com uma bela representação de seu argumento de construtor. Nesse caso, a representação XML de:
{"a": ["hello", XML("world")], "b": (1, 2)}
irá renderizar como:
<table>
<tr><td>a</td><td>:</td><td>hello<br />world</td></tr>
<tr><td>b</td><td>:</td><td>1<br />2</td></tr>
</table>
server-side DOM e parsing
elements
O ajudante DIV e todos os auxiliares derivados fornecem os métodos de pesquisa element
e elements
.
element
retorna o primeiro elemento filho correspondente a uma condição especificada (ou Nenhum, se não houver correspondência).
elements
retorna uma lista de todos os filhos correspondentes.
elemento e elementos use a mesma sintaxe para especificar a condição de correspondência, que permite três possibilidades que podem ser combinadas e combinadas: expressões semelhantes a jQuery, correspondência por valor de atributo exato, correspondência usando expressões regulares.
Aqui está um exemplo simples:
>>> a = DIV(DIV(DIV('a', _id='target', _class='abc')))
>>> d = a.elements('div#target')
>>> d[0][0] = 'changed'
>>> print a
<div><div><div id="target" class="abc">changed</div></div></div>
O argumento não denominado de elements
é uma string, que pode conter: o nome de uma tag, o id de uma tag precedido por um símbolo de libra, a classe precedida por um ponto, o valor explícito de um atributo entre colchetes.
Aqui estão 4 maneiras equivalentes de pesquisar a tag anterior por id:
>>> d = a.elements('#target')
>>> d = a.elements('div#target')
>>> d = a.elements('div[id=target]')
>>> d = a.elements('div', _id='target')
Aqui estão 4 maneiras equivalentes de pesquisar a tag anterior por classe:
>>> d = a.elements('.abc')
>>> d = a.elements('div.abc')
>>> d = a.elements('div[class=abc]')
>>> d = a.elements('div', _class='abc')
Qualquer atributo pode ser usado para localizar um elemento (não apenas id
e class
), incluindo vários atributos (o elemento function pode receber vários argumentos nomeados), mas somente o primeiro elemento correspondente será retornado.
target
é possível especificar vários critérios de pesquisa separados por uma vírgula:
>>> a = DIV(SPAN('a', _id='t1'), DIV('b', _class='c2'))
>>> d = a.elements('span#t1, div.c2')
ou equivalente
>>> a = DIV(SPAN('a', _id='t1'), DIV('b', _class='c2'))
>>> d = a.elements('span#t1', 'div.c2')
Se o valor de um atributo for especificado usando um argumento name, ele poderá ser uma string ou uma expressão regular:
>>> a = DIV(SPAN('a', _id='test123'), DIV('b', _class='c2'))
>>> d = a.elements('span', _id=re.compile('test\d{3}')
Um argumento nomeado especial dos ajudantes DIV (e derivados) é find
. Ele pode ser usado para especificar um valor de pesquisa ou uma expressão regular de pesquisa no conteúdo de texto da tag. Por exemplo:
>>> a = DIV(SPAN('abcde'), DIV('fghij'))
>>> d = a.elements(find='bcd')
>>> print d[0]
<span>abcde</span>
ou
>>> a = DIV(SPAN('abcde'), DIV('fghij'))
>>> d = a.elements(find=re.compile('fg\w{3}'))
>>> print d[0]
<div>fghij</div>
components
Aqui está um exemplo de listar todos os elementos em uma string html:
html = TAG('<a>xxx</a><b>yyy</b>')
for item in html.components: print item
parent
e siblings
parent
retorna o pai do elemento atual.
>>> a = DIV(SPAN('a'), DIV('b'))
>>> s = a.element('span')
>>> d = s.parent
>>> d['_class']='abc'
>>> print a
<div class="abc"><span>a</span><div>b</div></div>
>>> for e in s.siblings(): print e
<div>b</div>
Substituindo elementos
Elementos que são correspondidos também podem ser substituídos ou removidos especificando a replace
argumento. Observe que um A lista dos elementos correspondentes originais ainda é retornada como de costume.
>>> a = DIV(SPAN('x'), DIV(SPAN('y'))
>>> b = a.elements('span', replace=P('z')
>>> print a
<div><p>z</p><div><p>z</p></div>
replace
pode ser uma chamada. Neste caso, será passado o elemento original e espera-se que ele retorne o elemento de substituição:
>>> a = DIV(SPAN('x'), DIV(SPAN('y'))
>>> b = a.elements('span', replace=lambda t: P(t[0])
>>> print a
<div><p>x</p><div><p>y</p></div>
E se replace=None
, os elementos correspondentes serão removidos completamente.
>>> a = DIV(SPAN('x'), DIV(SPAN('y'))
>>> b = a.elements('span', replace=None)
>>> print a
<div></div>
flatten
O método flatten recursivamente serializa o conteúdo dos filhos de um determinado elemento em texto normal (sem tags):
>>> a = DIV(SPAN('this', DIV('is', B('a'))), SPAN('test'))
>>> print a.flatten()
thisisatest
Flatten pode ser passado um argumento opcional, render
, isto é, uma função que processa/achata o conteúdo usando um protocolo diferente. Aqui está um exemplo para serializar algumas tags na sintaxe wiki do Markmin:
>>> a = DIV(H1('title'), P('example of a ', A('link', _href='#test')))
>>> from gluon.html import markmin_serializer
>>> print a.flatten(render=markmin_serializer)
# titles
example of [[a link #test]]
No momento da escrita nós fornecemos markmin_serializer
e markdown_serializer
.
Parser
O objeto TAG também é um parser XML/HTML. Pode ler texto e converter em uma estrutura de árvore de ajudantes. Isso permite manipulação usando a API acima:
>>> html = '<h1>Title</h1><p>this is a <span>test</span></p>'
>>> parsed_html = TAG(html)
>>> parsed_html.element('span')[0]='TEST'
>>> print parsed_html
<h1>Title</h1><p>this is a <span>TEST</span></p>
Layout da página
As visualizações podem se estender e incluir outras visualizações em uma estrutura semelhante a uma árvore.
Por exemplo, podemos pensar em uma visualização "index.html" que estende "layout.html" e inclui "body.html". Ao mesmo tempo, "layout.html" pode incluir "header.html" e "footer.html".
A raiz da árvore é o que chamamos de visualização de layout. Assim como qualquer outro arquivo de modelo HTML, você pode editá-lo usando a interface administrativa web2py. O nome do arquivo "layout.html" é apenas uma convenção.
Aqui está uma página minimalista que estende a visualização "layout.html" e inclui a visualização "page.html":
{{extend 'layout.html'}}
<h1>Hello World</h1>
{{include 'page.html'}}
O arquivo de layout estendido deve conter um {{include}}
directiva, algo como:
<html>
<head>
<title>Page Title</title>
</head>
<body>
{{include}}
</body>
</html>
Quando a exibição é chamada, a exibição estendida (layout) é carregada e a exibição da chamada substitui a {{include}}
diretiva dentro do layout. O processamento continua recursivamente até que todos extend
e include
diretivas foram processadas. O modelo resultante é então traduzido em código Python. Note que, quando uma aplicação é compilada por bytecode, é este código Python que é compilado, e não os próprios arquivos de visão originais. Portanto, a versão compilada bytecode de uma determinada visualização é um único arquivo .pyc que inclui o código Python não apenas para o arquivo de exibição original, mas para toda a árvore de visualizações estendidas e incluídas.
extend
,include
,block
esuper
são diretivas especiais de modelo, não comandos do Python.
Qualquer conteúdo ou código que preceda o {{extend ...}}
A diretiva será inserida (e, portanto, executada) antes do início do conteúdo/código da visualização estendida. Embora isso não seja normalmente usado para inserir conteúdo HTML real antes do conteúdo da exibição estendida, ele pode ser útil como um meio de definir variáveis ou funções que você deseja disponibilizar para a exibição estendida. Por exemplo, considere uma visualização "index.html":
{{sidebar_enabled=True}}
{{extend 'layout.html'}}
<h1>Home Page</h1>
e um trecho de "layout.html":
{{if sidebar_enabled:}}
<div id="sidebar">
Sidebar Content
</div>
{{pass}}
Porque o sidebar_enabled
atribuição em "index.html" vem antes do extend
, essa linha é inserida antes do início do "layout.html", fazendo sidebar_enabled
disponível em qualquer lugar dentro do código "layout.html" (uma versão um pouco mais sofisticada é usada no bem vinda aplicativo).
Também vale a pena ressaltar que as variáveis retornadas pela função de controlador estão disponíveis não apenas na visão principal da função, mas também em todas as suas visualizações estendidas e incluídas.
O argumento de um extend
ou include
(isto é, o nome de exibição estendido ou incluído) pode ser uma variável python (embora não uma expressão python). No entanto, isso impõe uma limitação - visões que usam variáveis extend
ou include
instruções não podem ser compiladas bytecode. Como mencionado acima, as visualizações compiladas por bytecode incluem toda a árvore de visualizações estendidas e incluídas, portanto as visualizações estendidas e incluídas específicas devem ser conhecidas em tempo de compilação, o que não é possível se os nomes das visualizações forem variáveis (cujos valores não são determinados até que sejam executados Tempo). Como as visualizações de compilação de bytecode podem fornecer um aumento de velocidade significativo, usando variáveis em extend
e include
geralmente deve ser evitado, se possível.
Em alguns casos, uma alternativa ao uso de uma variável em um include
é simplesmente colocar regularmente {{include ...}}
diretivas dentro de um if...else
quadra.
{{if some_condition:}}
{{include 'this_view.html'}}
{{else:}}
{{include 'that_view.html'}}
{{pass}}
O código acima não apresenta nenhum problema para a compilação de bytecode porque não há variáveis envolvidas. Observe, no entanto, que a visualização compilada bytecode incluirá o código Python para "this_view.html" e "that_view.html", embora apenas o código para uma dessas visualizações seja executado, dependendo do valor de some_condition
.
Tenha em mente que isso só funciona include
- você não pode colocar {{extend ...}}
diretivas dentro if...else
blocos.
Os layouts são usados para encapsular a semelhança de páginas (cabeçalhos, rodapés, menus) e, embora não sejam obrigatórios, eles facilitarão a gravação e a manutenção do seu aplicativo. Em particular, sugerimos a criação de layouts que aproveitem as seguintes variáveis que podem ser definidas no controlador. O uso dessas variáveis conhecidas ajudará a tornar seus layouts intercambiáveis:
response.title
response.subtitle
response.meta.author
response.meta.keywords
response.meta.description
response.flash
response.menu
response.files
Exceto por menu
e files
, estas são todas as cordas e seu significado deve ser óbvio.
response.menu
menu é uma lista de 3-tuplas ou 4-tuplas. Os três elementos são: o nome do link, um booleano que representa se o link está ativo (é o link atual) e o URL da página vinculada. Por exemplo:
response.menu = [('Google', False, 'http://www.google.com', []),
('Index', True, URL('index'), [])]
O quarto elemento da tupla é um submenu opcional.
response.files
é uma lista de arquivos CSS e JS necessários para sua página.
Também recomendamos que você use:
{{include 'web2py_ajax.html'}}
no cabeçalho HTML, pois isso incluirá as bibliotecas jQuery e definirá algumas funções JavaScript compatíveis com versões anteriores para efeitos especiais e Ajax. "web2py_ajax.html" inclui o response.meta
tags na visualização, na base do jQuery, no datepicker do calendário e em todos os CSS e JS necessários response.files
.
Layout de página padrão
O "views/layout.html" que vem com o aplicativo de andaimes web2py bem vinda (despojado de algumas partes opcionais) é bastante complexo, mas tem a seguinte estrutura:
<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<title>{{=response.title or request.application}}</title>
...
<script src="{{=URL('static', 'js/modernizr.custom.js')}}"></script>
{{
response.files.append(URL('static', 'css/web2py.css'))
response.files.append(URL('static', 'css/bootstrap.min.css'))
response.files.append(URL('static', 'css/bootstrap-responsive.min.css'))
response.files.append(URL('static', 'css/web2py_bootstrap.css'))
}}
{{include 'web2py_ajax.html'}}
{{
# using sidebars need to know what sidebar you want to use
left_sidebar_enabled = globals().get('left_sidebar_enabled', False)
right_sidebar_enabled = globals().get('right_sidebar_enabled', False)
middle_columns = {0:'span12', 1:'span9', 2:'span6'}[
(left_sidebar_enabled and 1 or 0)+(right_sidebar_enabled and 1 or 0)]
}}
{{block head}}{{end}}
</head>
<body>
<!-- Navbar ================================================== -->
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="flash">{{=response.flash or ''}}</div>
<div class="navbar-inner">
<div class="container">
{{=response.logo or ''}}
<ul id="navbar" class="nav pull-right">
{{='auth' in globals() and auth.navbar(mode="dropdown") or ''}}
</ul>
<div class="nav-collapse">
{{if response.menu:}}
{{=MENU(response.menu)}}
{{pass}}
</div><!--/.nav-collapse -->
</div>
</div>
</div><!--/top navbar -->
<div class="container">
<!-- Masthead ================================================== -->
<header class="mastheader row" id="header">
<div class="span12">
<div class="page-header">
<h1>
{{=response.title or request.application}}
<small>{{=response.subtitle or ''}}</small>
</h1>
</div>
</div>
</header>
<section id="main" class="main row">
{{if left_sidebar_enabled:}}
<div class="span3 left-sidebar">
{{block left_sidebar}}
<h3>Left Sidebar</h3>
<p></p>
{{end}}
</div>
{{pass}}
<div class="{{=middle_columns}}">
{{block center}}
{{include}}
{{end}}
</div>
{{if right_sidebar_enabled:}}
<div class="span3">
{{block right_sidebar}}
<h3>Right Sidebar</h3>
<p></p>
{{end}}
</div>
{{pass}}
</section><!--/main-->
<!-- Footer ================================================== -->
<div class="row">
<footer class="footer span12" id="footer">
<div class="footer-content">
{{block footer}} <!-- this is default footer -->
...
{{end}}
</div>
</footer>
</div>
</div> <!-- /container -->
<!-- The javascript =============================================
(Placed at the end of the document so the pages load faster) -->
<script src="{{=URL('static', 'js/bootstrap.min.js')}}"></script>
<script src="{{=URL('static', 'js/web2py_bootstrap.js')}}"></script>
{{if response.google_analytics_id:}}
<script src="{{=URL('static', 'js/analytics.js')}}"></script>
<script type="text/javascript">
analytics.initialize({
'Google Analytics':{trackingId:'{{=response.google_analytics_id}}'}
});</script>
{{pass}}
</body>
</html>
Existem alguns recursos desse layout padrão que facilitam o uso e a personalização:
- Está escrito em HTML5 e usa o "modernizr" [modernizr] biblioteca para compatibilidade com versões anteriores. O layout atual inclui algumas instruções condicionais extras exigidas pelo IE e são omitidas por brevidade.
- Exibe ambos
response.title
eresponse.subtitle
que pode ser definido em um modelo ou um controlador. Se eles não estiverem configurados, ele adotará o nome do aplicativo como título - Inclui o
web2py_ajax.html
arquivo no cabeçalho que gerou todas as instruções de importação de link e script. - Ele usa uma versão modificada do Twitter Bootstrap para layouts flexíveis, que funciona em dispositivos móveis e re-organiza colunas para caber em telas pequenas.
- Ele usa "analytics.js" para se conectar ao Google Analytics.
- O
{{=auth.navbar(...)}}
exibe uma mensagem de boas-vindas ao usuário atual e links para as funções de autenticação, como login, logout, registro, alteração de senha, etc., dependendo do contexto. É uma fábrica auxiliar e sua saída pode ser manipulada como qualquer outro auxiliar. Ele é colocado em um{{try:}}...{{except:pass}}
caso a autenticação seja indefinida. - O
{{=MENU(response.menu)}}
exibe a estrutura do menu como<ul>...</ul>
. {{include}}
é substituído pelo conteúdo da visualização de extensão quando a página é renderizada.- Por padrão, ele usa uma coluna condicional de três (as barras laterais esquerda e direita podem ser desativadas pelas views de extensão)
- Ele usa as seguintes classes: header, main, footer
- Ele contém os seguintes blocos: statusbar, left_sidebar, center, right_sidebar, footer.
Em visualizações, você pode ativar e personalizar as barras laterais da seguinte maneira:
{{left_sidebar_enable=True}}
{{extend 'layout.html'}}
This text goes in center
{{block left_sidebar}}
This text goes in sidebar
{{end}}
Customizando o layout padrão
Personalizar o layout padrão sem edição é fácil porque o aplicativo de boas-vindas é baseado no Twitter Bootstrap, que é bem documentado e suporta temas. No web2py quatro arquivos estáticos que são relevantes para o estilo:
- "css/web2py.css" contém estilos específicos de web2py
- "css/bootstrap.min.css" contém o estilo CSS do Twitter Bootstrap [bootstrap] Bootstrap
- "css/web2py_bootstrap.css" contém substituindo alguns estilos do Bootstrap para atender às necessidades do web2py.
- "js/bootstrap.min.js", que inclui as bibliotecas para efeitos de menu, modais, painéis.
Para alterar cores e imagens de fundo, tente anexar o seguinte código ao layout.html header:
<style>
body { background: url('images/background.png') repeat-x #3A3A3A; }
a { color: #349C01; }
.header h1 { color: #349C01; }
.header h2 { color: white; font-style: italic; font-size: 14px;}
.statusbar { background: #333333; border-bottom: 5px #349C01 solid; }
.statusbar a { color: white; }
.footer { border-top: 5px #349C01 solid; }
</style>
É claro que você também pode substituir completamente os arquivos "layout.html" e "web2py.css" pelos seus.
Desenvolvimento móvel
Embora o layout.html padrão seja projetado para ser compatível com dispositivos móveis, às vezes é necessário usar exibições diferentes quando uma página é visitada por um dispositivo móvel.
Para facilitar o desenvolvimento de dispositivos móveis e de desktop, o web2py inclui @mobilize
decorador. Esse decorador é aplicado a ações que devem ter uma visualização normal e uma visualização móvel. Isso é demonstrado aqui:
from gluon.contrib.user_agent_parser import mobilize
@mobilize
def index():
return dict()
Observe que o decorador deve ser importado antes de usá-lo em um controlador. Quando a função "index" é chamado a partir de um browser normal (computador de mesa), web2py tornará o dicionário retornado usando a exibição "[controller] /index.html". No entanto, quando é chamado por um dispositivo móvel, o dicionário será processado por "[controller] /index.mobile.html". Observe que as visualizações para celular têm a extensão "mobile.html".
Como alternativa, você pode aplicar a seguinte lógica para tornar todas as visualizações compatíveis com dispositivos móveis:
if request.user_agent().is_mobile:
response.view.replace('.html', '.mobile.html')
A tarefa de criar as visualizações "* .mobile.html" é deixada para o desenvolvedor, mas sugerimos fortemente que você use o plugin "jQuery Mobile", que facilita muito a tarefa.
Funções nas visualizações
Considere este "layout.html":
<html>
<body>
{{include}}
<div class="sidebar">
{{if 'mysidebar' in globals():}}{{mysidebar()}}{{else:}}
my default sidebar
{{pass}}
</div>
</body>
</html>
e esta visão ampliada
{{def mysidebar():}}
my new sidebar!!!
{{return}}
{{extend 'layout.html'}}
Hello World!!!
Observe que a função é definida antes do {{extend...}}
statement - isso resulta na função que está sendo criada antes que o código "layout.html" seja executado, então a função pode ser chamada em qualquer lugar dentro de "layout.html", mesmo antes do {{include}}
. Observe também que a função está incluída na exibição estendida sem o =
prefixo.
O código gera a seguinte saída:
<html>
<body>
Hello World!!!
<div class="sidebar">
my new sidebar!!!
</div>
</body>
</html>
Observe que a função é definida em HTML (embora também possa conter código Python) para que response.write
é usado para escrever seu conteúdo (a função não retorna o conteúdo). É por isso que o layout chama a função de exibição usando {{mysidebar()}}
ao invés de {{=mysidebar()}}
. Funções definidas dessa maneira podem receber argumentos.
Blocos em views
A principal maneira de tornar a visão mais modular é usando {{block...}}s
e esse mecanismo é uma alternativa ao mecanismo discutido na seção anterior.
Para entender como isso funciona, considere aplicativos baseados no aplicativo de boas-vindas Welcome, que tem uma visualização layout.html. Esta visão é incluída na exibição default/index.html
através da {{extend 'layout.html'}}
. O conteúdo de layout.html predefine certos blocos com determinado conteúdo padrão, e estes são, portanto, incluídos em default/index.html.
Você pode substituir esses blocos de conteúdo padrão colocando o novo conteúdo dentro do mesmo nome de bloco. A localização do bloco no layout.html não é alterada, mas o conteúdo é.
Aqui está uma versão simplificada. Imagine isso é "layout.html":
<html>
<body>
{{include}}
<div class="sidebar">
{{block mysidebar}}
my default sidebar (this content to be replaced)
{{end}}
</div>
</body>
</html>
e esta é uma simples visão ampliada default/index.html
:
{{extend 'layout.html'}}
Hello World!!!
{{block mysidebar}}
my new sidebar!!!
{{end}}
Ele gera a seguinte saída, em que o conteúdo é fornecido pelo bloco principal na exibição de extensão, mas a classe DIV e a delimitadora vêm de layout.html. Isso permite a consistência entre as visualizações:
<html>
<body>
Hello World!!!
<div class="sidebar">
my new sidebar!!!
</div>
</body>
</html>
O layout.html real define vários blocos úteis e você pode adicionar mais facilmente para combinar com o layout desejado.
Você pode ter muitos blocos e, se um bloco estiver presente na exibição estendida, mas não na exibição de extensão, o conteúdo da exibição estendida será usado. Além disso, observe que, diferentemente das funções, não é necessário definir blocos antes {{extend ...}}
- mesmo se definido após o extend
, eles podem ser usados para fazer substituições em qualquer lugar na exibição estendida.
Dentro de um bloco, você pode usar a expressão {{super}}
para incluir o conteúdo do pai. Por exemplo, se substituirmos a vista de extensão acima por:
{{extend 'layout.html'}}
Hello World!!!
{{block mysidebar}}
{{super}}
my new sidebar!!!
{{end}}
Nós temos:
<html>
<body>
Hello World!!!
<div class="sidebar">
my default sidebar
my new sidebar!
</div>
</body>
</html>
Javascript nas visualizações
Os auxiliares podem ser usados em códigos externos, colocando-os em um modelo e incluindo o modelo, quando necessário. Por exemplo, se algum código javascript estiver em um arquivo "/views/my.js", ele poderá ser incluído em um arquivo de visualização:
<script>
{{include 'my.js'}}
</script>
No entanto, isso será ineficiente se houver muitas linhas de código javascript, mas apenas algumas linhas de conteúdo web2py gerados dinamicamente, como ajudantes. Uma alternativa é definir as variáveis web2py geradas dinamicamente em um bloco de javascript no modelo e, em seguida, carregar um arquivo javascript estático que simplesmente se refere a essas variáveis (é assim que "web2py_ajax.html" funciona - define várias variáveis JS, que são então usados por "web2py.js"). Então, no arquivo de visão:
<script>
var someVar = "{{=T('some phrase to be translated')}}";
var someURL = "{{=URL('default', 'myfunction')}}";
</script>
<script src="{{=URL('static', 'js/my.js')}}"></script>
ou equivalentemente usando o web2py ASSIGNJS
ajudante:
<script>
{{=ASSIGNJS(someVar = T('some phrase to be translated'),
someURL = URL('default', 'myfunction'))}};
</script>
<script src="{{=URL('static', 'js/my.js')}}"></script>
então em "my.js", someVar
e someURL
pode ser usado como variáveis javascript normais.