Nesta lição, vamos nos concentrar em como implementar o comportamento de um componente com regras e ações.
Ao criar componentes, pode-se escrever regras que consistem em uma expressão e uma ou mais ações. As ações serão executadas se a expressão for verdadeira. Uma regra consiste em três elementos:
Uma regra também sempre será atribuída a um estado:
<onenter>
: Este é o primeiro estado quando uma etapa é inserida. A interface do usuário não está disponível nesse estado, como resultado, você não pode usar ações relacionadas à interface do usuário. Se, no entanto, você quiser inicializar parâmetros para usá-los para mapeamento de interface do usuário, esse é o estado correto para fazer isso.<onresume>
: O segundo estado depois de <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ê sai da etapa atual ou do componente inteiro usando as step_transition
ações ou finish_workflow
. Como as transições não são interruptíveis, você não pode usar regras aqui que usam essas ações. No Estado, os recursos da etapa ainda existem, masonleave
não existem. onpause
<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 dentro de um estado são avaliadas em ordem arbitrária, portanto, a expressão de uma regra não deve depender de outra regra sendo verificada 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:
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 "Texto paginado" que mostra um texto de comprimento arbitrário em várias páginas:
<onevent> <rule id="next_page"> <expressão><![ CDATA[ #{event:command} == 'NEXT_PAGE' && #{page} < #{numberofpages} ]]></expression> <actions> <action ref="next"/> <action ref="settext"/> </actions> </rule> </onevent>
Dicas e truques:
-> espaços em branco serão excluídos da expressão, a menos que sejam marcados como cadeias de caracteres com aspas simples, para que você possa usar livremente novas linhas para tornar sua expressão legível.
->Esta expressão torna-se 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 <![CDATA[ ... ]]>
tag ao redor da expressão. A tag é obrigatória nesse caso. É uma palavra-chave XML que informa ao analisador que o que se segue não é marcação. Sem a <![CDATA[ ... ]]>
tag , essa expressão invalidaria o XML do nosso componente, pois contém os caracteres &
reservados a XML e <
o .
-> Adicione uma <![CDATA[ ... ]]>
tag a todas as suas expressões. Dessa forma, você não precisa pensar se está usando caracteres reservados para XML.
Quando sua regra está no <onevent>
estado 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:
{ "comando": "... ", "dispositivo": { "modalidade": "... ", "nome": "... ", "fonte": "... ", "descritor": "... " }, "carga útil": { "... ": "... ", "erro": "... " } }
Você só precisará de um subconjunto destes campos:
1. comando: O comando deste evento, por exemplo, "NEXT". O comando pode, por exemplo, corresponder a uma ID no layout ou na descrição do fluxo de trabalho do componente. Exemplo: #{event:command} == 'CANCEL'
2. device.modality: A origem do evento. Este 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, são dependentes da ação/manipulador que aciona o evento. Exemplo, #{event:payload.amount}
4. payload.error: Contém uma mensagem de erro se houver uma. 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 fala "NEXT" que os trabalhadores podem usar para confirmar que terminaram seu trabalho em uma tarefa ou produto específico. Eles também podem estar usando um dispositivo que dispara um evento com o comando "NEXT". Quando um botão de hardware é pressionado, ele gira através das opções disponíveis na tela. Você não deseja ativar a regra quando os botões de hardware estão 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
Vamos passar por algumas construções de regras que aparecem com relativa frequência:
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 <expression>1</expression>
.
<onresume>< rule id="init"> <expression>1</expression> <actions>< action ref="reset_counter"/> </actions> </rule> </onresume>
As regras dentro de um estado são avaliadas em ordem arbitrária. Em algumas situações, você precisa que as regras sejam executadas sequencialmente dentro da mesma etapa. Para isso, você pode usar um temporizador para acionar as regras em ordem sequencial. A ação de timer dispara manualmente um evento com um comando definido pelo usuário.
Como última ação da primeira regra, você adicionará uma ação de timer. 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 1:
Em nosso componente "Escolha", não usamos a <![CDATA[ ... ]]>
tag para manter o componente o mais simples possível para o aluno inicial. Como prática recomendada, recomendamos usar a tag em todas as suas expressões para eliminar uma possível fonte de erro.
<![CDATA[ ... ]]>
tag à nossa regra existente.Atribuição 2:
Vamos garantir que o usuário tenha certeza de sua escolha. Se, por exemplo, assim que escolhermos tortas de maçã "Apple" começarem a ser produzidas, podemos querer que o usuário reafirme:
Baixar fluxo de trabalho (pré-atribuição)
<command>
ui_dialog
à das opções. Parte da lógica da regra existente terá de ser movida para essa nova regra.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.