Nesta lição, vamos nos concentrar em como implementar o comportamento de um componente com regras e ações.
Já aprendemos que, ao criar seus próprios componentes, você escreverá regras que consistem em uma expressão e uma ou mais ações. A(s) ação(ões) será(ão) executada(s) se a expressão for verdadeira.
Regra
Uma regra consiste em três elementos:
- ID: Identificador de regra que deve ser exclusivo dentro de um escopo
- Expressão: Condição que aciona essa regra
- Ações: Referências ou definições de ações que são executadas quando essa regra é acionada
Uma regra também será sempre atribuída a um estado:
Estados
<onenter>:
Esse é o primeiro estado quando uma etapa é inserida. A interface do usuário não está disponível nesse estado e, como resultado, não é possível usar ações relacionadas à interface do usuário. Se, no entanto, você quiser inicializar parâmetros para usá-los no mapeamento da interface do usuário, esse é o estado correto para isso.<onresume>:
O segundo estado após <onenter>. Nesse estado, a interface do usuário está disponível e você pode modificar o layout carregado com as ações de atualização da interface do usuário.<onpause>
e <onleave>:
Esses estados ocorrem sempre que você deixa a etapa atual ou todo o componente usando as ações step_transition
ou finish_workflow
. Como as transições não podem ser interrompidas, não é possível usar aqui regras que utilizem essas ações. No estadoonpause
, os recursos da etapa ainda existem; no onleave,
eles não existem.<onevent>:
Este é provavelmente o estado mais importante. As regras definidas nesse estado serão verificadas sempre que um evento for processado. Todas as regras relacionadas às interações com o usuário são definidas nesse estado.
As regras em um estado são avaliadas em ordem arbitrária, portanto, a expressão de uma regra não deve depender da verificação de outra regra antes dela.
Por outro lado, as ações dentro de uma regra são executadas na ordem em que você as escreve.
Ordem de avaliação/execução:
- As regras são verificadas em ordem arbitrária.
- As ações dentro de uma regra são executadas em ordem sequencial.
Expressões
A estrutura geral de uma expressão é composta de operandos (por exemplo, variáveis de contexto) e operadores (por exemplo, '=' ou '>'), como em qualquer linguagem de programação.
Operadores suportados: +, -, &&, ||, !, /, ==, >, >=, <, <=, %, *, !=
Vamos dar uma olhada em outro exemplo simples do componente "Paginated Text", que mostra um texto de comprimento arbitrário em várias páginas:
<onevent>
<rule id="next_page">
<expression><![CDATA[
#{event:command} == 'NEXT_PAGE' && #{page} < #{numberofpages}
]]></expression>
<actions>
<action ref="next"/>
<action ref="settext"/>
</actions>
</rule>
</onevent>
Dicas e truques:
- Os espaços em branco serão excluídos da expressão, a menos que sejam marcados como cadeias de caracteres com aspas simples, portanto, você pode usar livremente novas linhas para tornar sua expressão legível.
- Essa expressão se torna verdadeira quando o botão
name="NEXT_PAGE"
é pressionado e a página atual não é a última página. - Você deve ter notado a tag
<![CDATA[ ... ]]>
ao redor da expressão. A tag é necessária nesse caso. É uma palavra-chave XML que informa ao analisador que o que vem a seguir não é marcação. Sem a tag <![CDATA[ ... ]]>
, essa expressão invalidaria o XML do nosso componente porque contém os caracteres &
e <
reservados para XML. - Adicione uma tag
<![CDATA[ ... ]]>
a todas as suas expressões. Dessa forma, você não precisa pensar se está usando caracteres reservados para XML.
Eventos
Quando sua regra está no estado <onevent>
de uma etapa, você pode reagir a eventos e usar as propriedades do evento em sua expressão. A estrutura de um evento é a seguinte:
{
"command": "...",
"device":
{
"modality": "...",
"name": "...",
"source": "...",
"descriptor": "..."
},
"payload":
{
"...": "...",
"error": "..."
}
}
Você só precisará de um subconjunto desses campos:
1. comando: O comando desse evento, por exemplo, "NEXT". O comando pode, por exemplo, corresponder a uma ID no layout ou na descrição do fluxo de trabalho do seu componente. Exemplo: #{event:command} == 'CANCEL'
2. dispositivo.modalidade: A origem do evento. Esse campo pode ser acessado usando uma notação curta.
A expressão #{event(SPEECH):command=='NEXT' é equivalente à expressão #{event:device.modality} == 'SPEECH' && #{event:command} == 'NEXT'. A modalidade depende do emissor do evento. Exemplo, #{event:device.modality} == 'MENU_SELECTION'
3. Carga útil: A estrutura/campos da carga útil dependem da ação/manipulador que aciona o evento. Exemplo, #{event:payload.amount}
4. payload.error: Contém uma mensagem de erro, se houver. Exemplo, #{event:payload.error}
Você pode restringir as fontes de eventos para garantir que uma regra seja acionada somente quando o evento for causado por uma modalidade de entrada específica. Por exemplo, você pode ter um comando de voz "NEXT" que os funcionários podem usar para confirmar que terminaram o trabalho em uma determinada tarefa ou produto. Eles também podem estar usando um dispositivo que aciona um evento com o comando "NEXT". Quando um botão de hardware é pressionado, ele percorre as opções disponíveis na tela. Você não quer ativar a regra quando os botões de hardware estiverem sendo usados, portanto, especifique a modalidade: #{event(SPEECH):command} == 'NEXT'.
Fontes de eventos gerais (modalidades): FALA, GESTO, TECLADO, CÓDIGO DE BARRAS, HW_KEYS, CAMERA_PICTURE, MENU_SELECTION, MEDIA_INPUT
Exemplos
Vamos examinar algumas construções de regras que aparecem com relativa frequência:
Inicialização e desmontagem
Nosso primeiro exemplo aborda um caso de uso típico: Executar ações automaticamente ao entrar ou sair de um componente.
Dicas e truques: Algumas regras precisam ser executadas incondicionalmente. Para isso, você pode definir a expressão como <expressão>1</expressão>.
<onresume>
<rule id="init">
<expression>1</expression>
<actions>
<action ref="reset_counter"/>
</actions>
</rule>
</onresume>
Execução sequencial de regras
As regras em um estado são avaliadas em uma ordem arbitrária. Em algumas situações, você precisa que as regras sejam executadas sequencialmente na mesma etapa. Para isso, você pode usar um timer para acionar as regras em ordem sequencial. A ação do temporizador aciona manualmente um evento com um comando definido pelo usuário.
Como última ação da primeira regra, você adicionará uma ação de cronômetro. O comando definido pelo usuário pode então ser adicionado à expressão da segunda regra.
<onevent>
<rule id="first_rule">
<expression><![CDATA[ #{event:command}=='VALID' ]]></expression>
<actions>
<action ref="do_something"/>
<setvar id="increment_counter">
<context_of>workflow</context_of>
<context_update>
<param name="counter" type="long">#{counter} + 1</param>
</context_update>
</setvar>
<timer id="check_counter_trigger" command="CHECK_COUNTER" delay="0"/>
</actions>
</rule>
<rule id="second_rule">
<expression><![CDATA[ #{event:command}=='CHECK_COUNTER' && #{counter} >= #{max_iterations} ]]></expression>
<actions>
<finish_workflow id="exit"/>
</actions>
</rule>
</onevent>
Atribuição
Vamos entrar em ação:
Atribuição 1:
Em nosso componente "Choice", não usamos a tag <![CDATA[ ... ]]>
para manter o componente o mais simples possível para o aluno inicial. Como prática recomendada, recomendamos o uso da tag em todas as suas expressões para eliminar uma possível fonte de erro.
- Adicione a tag
<![CDATA[ ... ]]>
à nossa regra existente.
Atribuição 2:
Vamos garantir que o usuário tenha certeza de sua escolha. Se, por exemplo, assim que escolhermos "Apple", as tortas de maçã começarem a ser produzidas, talvez queiramos que o usuário confirme novamente:
- Leia mais sobre a ação ui_dialog
- Adicione uma caixa de diálogo ao componente que mostre o valor selecionado e peça ao usuário para confirmar a seleção.
Faça o download do fluxo de trabalho (pré-atribuição)
Ajuda e recursos
- Para o Exercício 2, você terá de criar uma nova regra que reaja ao
<command>
das opções do ui_dialog
. Parte da lógica da regra existente terá de ser transferida para essa nova regra.
Solução
Componente de download (pós-atribuição)
Com isso, você terminou a quarta lição. Na quinta lição, examinaremos algumas limitações da definição de fluxos de trabalho apenas com XML e como você pode usar JavaScript em fluxos de trabalho para resolver esses problemas.