A veces, durante el desarrollo del flujo de trabajo, las herramientas que hemos discutido hasta este punto no serán suficientes para implementar la lógica requerida. Normalmente, esto ocurre siempre que se necesitan manipular los datos de entrada sin procesar, por ejemplo, antes de compararlos en una expresión o antes de guardarlos en una variable de contexto. En estos casos, la opción de utilizar nuestro motor JavaScript (JS) integrado en el marcado del flujo de trabajo debería ofrecer una solución viable.
Cualquier uso de JavaScript en un flujo de trabajo siempre debe estar dentro de una <![CDATA[ ... ]]>
etiqueta para evitar errores del analizador XML. Un ámbito JS se abre y se cierra mediante ?{ ... }?
. Puede acceder a las variables de contexto desde dentro del ámbito JS mediante context.variable_name
. Para acceder a los datos de eventos, utilizaría de manera similar, por ejemplo: event.field
<setvar id="add_digit_from_speech_command"> <context_of>workflow</context_of> <context_update> <param name="number" type="long"><![ CDATA[ ?{ context.number + number(event.command.substr(event.command.length - 1, event.command.length)) }? ]] ></param> </context_update> </setvar>
Como puede ver en el ejemplo anterior, puede escribir JS nativo arbitrario. Esto también puede abarcar varias líneas y un manejo más complejo. Verás algunos ejemplos más en el próximo artículo.
Hay algunas funciones incrustadas que se pueden utilizar directamente en el XML de flujo de trabajo sin abrir un contexto JS. Algunos de estos ejemplos se utilizan regularmente en casos de uso específicos:
El siguiente ejemplo contiene las toUpperCase
funciones ,trim,
y substring
.
<rule id="speak_material">< expression><![ CDATA[ #{evento:comando} == toUpperCase('#{material_name}') ]]></expression> <actions> <setvar id="set_material_type"> <context_update> <param name="material_type" type="string">trim(substring(#{material_name}, 0, 3))</param> </context_update> </setvar> </actions> </rule>
El anterior es un ejemplo típico, porque los comandos de voz siempre se emiten en mayúsculas. Si desea comparar un comando de voz con algún contenido del flujo de trabajo, siempre debe transformarlo también a mayúsculas.
Consejos y trucos: No utilice espacios en blanco para una mejor legibilidad del código dentro de una param
etiqueta de tipo string
, ya que se convertiría en parte de la cadena que está manipulando. Por ejemplo, daría como resultado, por ejemplo MAT_
, <param name="material_type" type="string">trim(substring(#{material_name}, 0, 3)) </param>
(donde _ es un espacio en blanco) aunque haya utilizado trim.
Veamos algunos ejemplos más de casos de uso en los que el motor JS resulta útil:
A veces es necesario acceder a los datos de forma dinámica (en función del contenido de otra variable de contexto):
<setvar id="set_step"> <context_update> <param name="step" type="object"><![ CDATA[ ?{ context.steps[context.current_step_index]}? ]]></param> </context_update> </setvar>
Si bien también puede crear varias acciones y reglas para implementar esto, JS permite la brevedad:
<setvar id="set_text_color"> <context_update> <param name="label_text_color" type="string"><![ CDATA[ ?{ (context.urgente)? 'red' : 'negro' }? ]]></param> </context_update> </setvar>
JavaScript también te ayuda a generar o manipular objetos. En el siguiente ejemplo, queremos permitir que el trabajador use comandos de voz para expresar una cantidad de 0 a 99. Cada comando de voz debe agregarse a la gramática de voz por separado, pero usando JavaScript podemos acortar esto a:
<action id="add_amount_speech_commands" type="speech_modify_commands_in_grammar"> <param name="slot">wf_editor_slot</param> <param name="commands"><![ CDATA[ ?{ Array.apply(null, {length: 100}) .map(Number.call, Number) .map(function(e) { return { 'name': 'AMOUNT ' + (e), 'description': 'AMOUNT [0-99]'} } )}? ]] ></param> <param name="modificación">add_commands</param> </action>
También hay casos de uso en los que JS ayuda en las expresiones. En el siguiente ejemplo, procesamos un evento que se emite cuando se desconecta un dispositivo de terceros. Usamos JS para buscar una cadena de direcciones MAC para el MAC del dispositivo desconectado.
<rule id="device_vanished"> <expression><![ CDATA[ #{event:command}== 'DEVICEVANISHED' && ?{ context.mac.search(evento.mac)>-1}?]] ></expresión> <acciones> <acción ref="back_to_start"/> </acciones> </regla>
Nota: El uso de JavaScript está limitado para las expresiones. El contenido de todas las expresiones se recortará para eliminar todos los saltos de línea y espacios en blanco que puedan romper la lógica. Por lo tanto, no puede utilizar varias líneas de JavaScript en las expresiones.
Otro caso de uso típico de JS es el widget comodín . Dado que aún no hemos introducido el lay-outing, no veremos un ejemplo aquí, pero la documentación del widget tiene uno.
En la versión actual de nuestro componente, la salida de nuestra elección está en mayúsculas y se muestra como tal en la interfaz de usuario del siguiente componente. Hagamos que se vea un poco mejor:
Descargar componente (pre-asignación)
A continuación se muestra una solución ejemplar:
<rule id="choice_made"> <expression><![ CDATA[ #{evento:comando} == 'APPLE' || #{evento:comando} == 'PEAR' ]]></expresión> <acciones> <setvar id="save_choice"> <context_of>workflow</context_of> <context_update> <param name="choice" type="string"><![ CDATA[ ?{ event.command.slice(0,1) + event.command.slice(1).toLowerCase() }? ]] ></param> </context_update> </setvar> <action ref="show_confirmation_dialog"/> </actions> </rule>
Descargar componente (posterior a la asignación)
En la siguiente lección, finalmente veremos cómo diseñar la interfaz de usuario de un componente.