diff --git a/DEVELOPERS.md b/DEVELOPERS.md index 599c02ec2bde1116abcd12fea32e12cf0e4cf0ba..8c4b21f9d0e047351e72430c894cc5a9554d8c7f 100644 --- a/DEVELOPERS.md +++ b/DEVELOPERS.md @@ -56,15 +56,13 @@ L'interface s'appuie sur les principes de **material design** et de **responsive L'état de la session, des modules, des paramètres et des résultats numériques est conservé par JaLHyd. Seules les représentations graphiques sont conservées par la couche ngHyd. -#### formulaires - -nodes +Pour chaque module chargé en session, un arbre d'objets partant d'une instance de `FormulaireDefinition` représente la structure des éléments à l'écran : groupes de champs (répétables ou non), champs, listes déroulantes. Ces éléments sont déclarés dans les fichiers du dossier `src/app/formulaire`. -ngparam +#### formulaires -form*, form-compute*, form-result* +Les formulaires dérivent de `FormulaireBase`. Lors de leur instanciation, ils se chargent de lire leur configuration (voir "configuration/modules" ci-dessous) et instancier les éléments enfants qui y sont déclarés : groupes de champs ("fieldset"), groupes de champs répétables ("fieldset_container"), paramètres d'entrée ("ngparam"), listes déroulantes ("select_field"). Ensuite le formulaire est lié au Nub de JaLHyd correspondant au module créé. -#### résultats +Chaque formulaire est associé à une instance d'une classe `FormCompute*` et une instance d'une classe `FormResult*`. La première est chargée d'exécuter le Nub de JaLHYd associé au formulaire, et de transmettre les résultats de calcul à la seconde. La seconde est chargée d'organiser les résultats (par défaut les grouper en résultats fixes / résultats variés) afin de faciliter leur représentation par les composants graphiques. ### configuration @@ -134,7 +132,7 @@ Le dossier `scripts` contient des scripts d'aide à la compilation, utilisés pa ## Ajouter un module de calcul -Dans cet exemple nous considérerons le module fictif "Addition" proposé dans la documentation de JaLHyd (voir ci-dessous). +Dans cet exemple nous considérerons le module fictif "Addition" proposé dans la documentation de JaLHyd (voir ci-dessous), tout en ajoutant des informations utiles pour des cas plus complexes. ### JaLHyd @@ -240,29 +238,167 @@ Dans les fichiers `locale/messages.*.json` : ### classes de formulaire personnalisées -2. **Si nécessaire** créer la classe du formulaire dans _src/app/formulaire/definition/concrete_ . Une classe de base gérant la majorité des cas est déjà disponible, en général cette étape n'est pas nécessaire +En général la classe `FormulaireBase` est suffisante pour gérer un nouveau module, et est instanciée automatiquement par `FormulaireService` lors de la création d'un nouveau module. Elle agrège es instances de `FormComputeFixedVar` et `FormResultFixedVar`. - - Par ex : _FormulaireMaCalculette_ dans _src/app/formulaire/definition/concrete/form-ma-calculette.ts_ +Mais dans des cas plus complexes, par exemple si le module contient des listes déroulantes ou des sous-modules, répétables ou non, il est nécessaire de créer de nouvelles classes de formulaires dérivées de celles-ci. - Ces classes concrètes sont construites par composition des classes dans _src/app/formulaire/definition_ : - - _form-def-*_ : définition/description du formulaire. - - _FormDefSection_ : avec paramètre à varier - - _FormDefParamToCalculate_ : avec paramètre à calculer - - etc... - - _form-compute-*_ : aspects calculatoires - - _form-result-*_ : affichage des résultats +Dans un tel cas, créer la classe du formulaire dans un nouveau fichier, dans le dossier `src/app/formulaire/definition/concrete/`/ Par exemple `form-macrorugo-compound.ts`. - On peut soit composer la classe concrète directement avec ces classes, soient dériver ces dernières et composer avec. +Si les mécanismes de calcul ou de récupération des résultats doivent être modifiés, créer les classes nécessaires dans le dossier `src/app/formulaire/definition`, par exemple `form-compute-macrorugo-compound.ts` et `form-result-macrorugo-compound.ts`. Sinon, agréger des classes `FormCompute*` et `FormResult*` existantes. +Si une nouvelle classe de formulaire a été créée, ajouter un `case` dans la méthode `newFormulaire()` de `FormulaireService`, dand `src/app/services/formulaire.service.ts`. Exemple : -5. **Si une nouvelle classe a été créée à l'étape 2**, dans la méthode _FormulaireService.newFormulaire()_, compléter le _switch_ pour fournir la classe à instancier. +```TypeScript +case CalculatorType.Trigo: + f = new FormulaireTrigo(); + break; +``` ### si le module agrège des modules enfants +La traduction des variables des modules enfants doit aussi être ajoutée dans les fichiers de langues, dans le dossier de configuration du module. + +#### si ces modules enfants sont répétables ("fs_container) + +Il est nécessaire de créer une nouvelle classe de formulaire dérivée de `FormulaireBase` (voir "classes de formulaire personnalisées" ci-dessus), en s'inspirant de `FormulaireMacrorugoCompound` par exemple. Notamment, implémenter ou surcharger les méthodes : + + * `createFieldset()` + * `moveFieldsetUp()` + * `moveFieldsetDown()` + * `removeFieldset()` + * `completeParse()` + * `update()` (action "newFieldset") + +Dans la méthode `create()` de `CalculatorListComponent`, dans le fichier `src/app/components/calculator-list/calculator-list.component.ts`, ajouter la création d'un enfant par défaut. Exemple pour `MacrorugoCompound` : + +```TypeScript +if (f instanceof FormulaireMacrorugoCompound) { + for (const e of f.allFormElements) { + if (e instanceof FieldsetContainer) { + e.addFromTemplate(0, 0, f.mrcNub.children[0]); + break; + } + } +} +``` + +Dans cet exemple, on ajoute l'interface pour le premier enfant du Nub (instancié par JaLHyd), à l'élément de formulaire de type `FieldsetContainer` (ici, il n'y en a qu'un). + +Ajouter ensuite la création de fieldsets pour les enfants existants, dans la méthode `createFormulaire()` de `FormulaireService`, dans le fichier `src/app/services/formulaire.service.ts`. Exemple pour `ParallelStructures` : + +```TypeScript +if (f.currentNub instanceof ParallelStructure) { + for (const struct of f.currentNub.structures) { + for (const e of f.allFormElements) { + if (e instanceof FieldsetContainer) { + e.addFromTemplate(0, undefined, struct); + } + } + } +} +``` + +Dans chaque fichier de langue du dossier `src/locale`, ajouter les traductions pour le nom type d'enfant (voir la documentation développeurs de JaLHyd), au singulier et au pluriel sous les clés `INFO_CHILD_TYPE_typedenfant` et `INFO_CHILD_TYPE_typedenfant_PLUR`. Par exemple pour le type d'enfant `Macrorugo` en français : + +```json +"INFO_CHILD_TYPE_MACRORUGO": "radier", +"INFO_CHILD_TYPE_MACRORUGO_PLUR": "radiers", +``` + ### si le formulaire comprend des listes déroulantes +Il est nécessaire de créer une nouvelle classe de formulaire dérivée de `FormulaireBase` (voir "classes de formulaire personnalisées" ci-dessus), en s'inspirant de FormulaireTrigo par exemple. Notamment, implémenter ou surcharger les méthodes : + + * `afterParseFieldset()` + * `parseOptions()` + * `update()` (appeler `reset()` lors de l'action "propertyChange") + +#### configuration + +Dans le fichier de configuration du module, ajouter la définition des listes déroulantes dans "fields" notamment leur **source** (voir "sources" plus bas), ainsi que leur valeur par défaut dans le "fieldset" parent. Exemple dans `trigo.config.json` + +```json +{ + "id": "fs_trigo", + "type": "fieldset", + "defaultOperation": "COS", + "defaultUnit": "DEG", + "fields": [ + { + "id": "select_operation", + "type": "select", + "source": "trigo_operation" + }, + { + "id": "select_unit", + "type": "select", + "source": "trigo_unit" + } + ] +}, +``` + +Dans ce même fichier de configuration, dans le dernier élément "options", ajouter une entrée par liste déroulante : + +```json +… +{ + "type": "options", + "operationSelectId": "select_operation", + "unitSelectId": "select_unit", + … +``` + +#### sources + +Chaque liste déroulante est associée à une **source** (voir "configuration" plus haut), qui détermine quels sont les choix possibles. Pour ajouter une source, modifier la méthode `parseConfig()` de la classe `SelectField`, dans le fichier `src/app/formulaire/select-field.ts`. Exemple pour "trigoOperation" : + +```TypeScript +case "trigo_operation": // (cos, sin…) + for (let j = 0; j < Object.keys(TrigoOperation).length / 2; j++) { + this.addEntry(new SelectEntry(this._entriesBaseId + j, j)); + } + break; +``` + +#### lien avec les propriétés + +Les listes déroulantes doivent être liées à des **propriétés** du Nub. Pour ce faire, modifier la classe `FieldSet` dans le fichier `src/app/formulaire/fieldset.ts` comme suit (exemple pour le module `Trigo`). + +Ajouter un `case` dans la fonction `updateFields()` + +```TypeScript +case "fs_trigo": // Trigo + this.setSelectValueFromProperty("select_operation", "trigoOperation"); + this.setSelectValueFromProperty("select_unit", "trigoUnit"); + break; +``` + +Ajouter un `case` dans la fonction `update()` + +```TypeScript +case "select_operation": // Trigo + this.setPropValue("trigoOperation", data.value.value); + break; +case "select_unit": // Trigo + this.setPropValue("trigoUnit", data.value.value); + break; +``` + +Dans la fonction `parseConfig()`, ajouter un appel par à `setPropertyValueFromConfig()` pour chaque liste déroulante. + +```TypeScript + this.setPropertyValueFromConfig(json, "defaultOperation", "trigoOperation", TrigoOperation); + this.setPropertyValueFromConfig(json, "defaultUnit", "trigoUnit", TrigoUnit); +``` + ### documentation Pour chaque langue, ajouter un fichier .md dans les dossiers `docs-*/calculators`, puis placer ce nouveau fichier dans la hiérarchie de la documentation, en ajoutant son chemin dans les fichiers `mkdocs-*.yml`. Lier ce fichier au module via la clé `help` du bloc d'options de la configuration du module. Exemple pour un fichier de documentation dont le chemin est `calculators/math/addition.md` : `"help" : "math/addition.html"` (MkDocs convertit les fichiers MarkDown en HTML) + +### tests unitaires + +Plusieurs tests unitaires passent en revue les modules pour les tester un par un. Pour que le nouveau module soit testé, son `CalculatorType` doit être ajouté à la liste dans le fichier `e2e/tested_calctypes.ts. + \ No newline at end of file