Parfois, au cours du développement d'un flux de travail, les outils dont nous avons parlé jusqu'à présent ne suffiront pas à mettre en œuvre la logique requise. Cela se produit généralement lorsque vous devez manipuler les données d'entrée brutes, par exemple avant de les comparer dans une expression ou de les enregistrer dans une variable contextuelle. Dans ces cas, l'option d'utiliser notre moteur JavaScript (JS) intégré dans le balisage du flux de travail devrait offrir une solution viable.
Toute utilisation de JavaScript dans un flux de travail doit toujours se faire à l'intérieur d'une balise < ![CDATA[ ... ]]>
afin d'éviter les erreurs de l'analyseur XML. Une portée JS est ouverte et fermée à l'aide de ?{ ..
. } ?.
Vous pouvez accéder aux variables de contexte à l'intérieur de la portée JS en utilisant context.variable_name
. Pour accéder aux données d'un événement, vous devez utiliser, par exemple, 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>
Comme vous pouvez le voir dans l'exemple ci-dessus, vous pouvez écrire des JS natifs arbitraires. Cela peut également s'étendre sur plusieurs lignes et sur des manipulations plus complexes. Vous trouverez d'autres exemples à la page suivante.
Fonctions intégrées
Il existe quelques fonctions intégrées que vous pouvez utiliser directement dans le flux de travail XML sans ouvrir un contexte JS. Certains de ces exemples sont régulièrement utilisés dans des cas d'utilisation spécifiques :
- existe : existe(#{shelve})
- toUppercase : toUppercase( '#{nom_du_matériel} ' )
- toLowercase: toLowercase( '#{nom_du_matériel} ' )
- trim : trim( # {nom_du_matériau} )
- contains: contains( # {first_code}, #{second_code})
- startsWith : startsWith( # {first_code}, #{second_code})
- endsWith: endsWith( # {first_code}, #{second_code})
- equals : equals( # {first_code}, #{second_code})
- substring: substring( # {nom_du_matériau}, 0, 3)
L'exemple ci-dessous contient les fonctions toUpperCase
, trim
et substring
.
<rule id="speak_material">
<expression><![CDATA[ #{event:command} == 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>
L'exemple ci-dessus est typique, car les commandes vocales sont toujours émises en majuscules. Si vous souhaitez comparer une commande vocale à un contenu dans votre flux de travail, vous devez toujours la transformer en majuscules.
Trucs et astuces: N'utilisez pas d'espace blanc pour améliorer la lisibilité du code dans une balise param
de type string
, car il deviendrait partie intégrante de la chaîne que vous manipulez. Par exemple, <param name="material_type" type="string">trim(substring(#{nom_matériel}, 0, 3)) </param>
donnerait par exemple MAT_
(où _ est un espace blanc) même si vous avez utilisé trim.
Exemple
Examinons quelques autres exemples de cas d'utilisation où le moteur JS s'avère utile :
Accès dynamique aux données
Il est parfois nécessaire d'accéder à des données de manière dynamique (en fonction du contenu d'une autre variable contextuelle) :
<setvar id="set_step">
<context_update>
<param name="step" type="object"><![CDATA[ ?{context.steps[context.current_step_index]}? ]]></param>
</context_update>
</setvar>
Manipulation conditionnelle des données
Bien qu'il soit possible de créer plusieurs actions et règles pour mettre cela en œuvre, JS permet d'être plus concis :
<setvar id="set_text_color">
<context_update>
<param name="label_text_color" type="string"><![CDATA[ ?{ (context.urgent)? 'red' : 'black' }? ]]></param>
</context_update>
</setvar>
Génération et manipulation d'objets
JavaScript permet également de générer ou de manipuler des objets. Dans l'exemple ci-dessous, nous voulons permettre au travailleur d'utiliser des commandes vocales pour exprimer un montant compris entre 0 et 99. Chaque commande vocale doit être ajoutée séparément à la grammaire vocale, mais en utilisant JavaScript, nous pouvons raccourcir ce processus :
<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="modification">add_commands</param>
</action>
Dans les expressions
Il existe également des cas d'utilisation où JS aide à l'expression. Dans l'exemple ci-dessous, nous traitons un événement qui est émis lorsqu'un appareil tiers est déconnecté. Nous utilisons JS pour rechercher dans une chaîne d'adresses MAC le MAC de l'appareil déconnecté.
<rule id="device_vanished">
<expression><![CDATA[ #{event:command}== 'DEVICEVANISHED' && ?{context.mac.search(event.mac)>-1}?]]></expression>
<actions>
<action ref="back_to_start"/>
</actions>
</rule>
Notez que l'utilisation de JavaScript est limitée aux expressions: Le contenu de toutes les expressions sera découpé pour supprimer tous les retours à la ligne et les espaces qui pourraient rompre la logique. Par conséquent, vous ne pouvez pas utiliser plusieurs lignes de JavaScript dans les expressions.
Widget Wildcard
Un autre cas d'utilisation typique de JS est le widget Wildcard. Comme nous n'avons pas encore introduit la mise en page, nous ne verrons pas d'exemple ici, mais la documentation sur les widgets en propose un.
Affectation
Affectation 1 :
Dans la version actuelle de notre composant, le résultat de notre choix est tout en majuscules et s'affiche comme tel dans l'interface utilisateur du composant suivant. Faisons en sorte que cela soit un peu plus joli :
- Utilisez JavaScript ou des fonctions intégrées pour enregistrer le choix résultant dans une majuscule plus naturelle.
Télécharger le composant
Solution
Vous trouverez ci-dessous une solution exemplaire :
<rule id="choice_made">
<expression><![CDATA[ #{event:command} == 'APPLE' || #{event:command} == 'PEAR' ]]></expression>
<actions>
<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>
Composant de téléchargement (après l'affectation)
Dans la prochaine leçon, nous verrons enfin comment concevoir l'interface utilisateur d'un composant.