From 8504d3acc43173e88d8d36e39c1a3a2e9d5a75e1 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Wed, 5 Jun 2019 15:51:42 +0200
Subject: [PATCH] =?UTF-8?q?Ajout=20composant=20et=20=C3=A9l=C3=A9ment=20de?=
 =?UTF-8?q?=20formulaire=20pour=20la=20nouvelle=20Pab?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/app/app.module.ts                         |   2 +
 src/app/calculators/pab/pab.config.json       |  45 +-----
 .../field-set/field-set.component.ts          |   6 +-
 .../calculator.component.html                 |   8 +-
 .../calculator.component.ts                   |  19 +--
 .../pab-table/pab-table.component.html        |  15 ++
 .../pab-table/pab-table.component.scss        |  25 +++
 .../pab-table/pab-table.component.ts          | 153 ++++++++++++++++++
 .../definition/concrete/form-pab.ts           | 129 +++++----------
 .../formulaire/definition/form-definition.ts  |  11 ++
 src/app/formulaire/pab-table.ts               |  18 +++
 src/locale/messages.en.json                   |   1 +
 src/locale/messages.fr.json                   |   1 +
 13 files changed, 293 insertions(+), 140 deletions(-)
 create mode 100644 src/app/components/pab-table/pab-table.component.html
 create mode 100644 src/app/components/pab-table/pab-table.component.scss
 create mode 100644 src/app/components/pab-table/pab-table.component.ts
 create mode 100644 src/app/formulaire/pab-table.ts

diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 69328bd5f..25698c7d5 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -76,6 +76,7 @@ import { VarResultsComponent } from "./components/fixedvar-results/var-results.c
 import { LogEntryComponent } from "./components/log-entry/log-entry.component";
 import { ParamLinkComponent } from "./components/param-link/param-link.component";
 import { SelectModelFieldLineComponent } from "./components/select-model-field-line/select-model-field-line.component";
+import { PabTableComponent } from "./components/pab-table/pab-table.component";
 
 import { DialogConfirmEmptySessionComponent } from "./components/dialog-confirm-empty-session/dialog-confirm-empty-session.component";
 import { DialogConfirmCloseCalcComponent } from "./components/dialog-confirm-close-calc/dialog-confirm-close-calc.component";
@@ -176,6 +177,7 @@ const appRoutes: Routes = [
     NgParamInputComponent,
     PabResultsComponent,
     PabResultsTableComponent,
+    PabTableComponent,
     ParamComputedComponent,
     ParamFieldLineComponent,
     ParamLinkComponent,
diff --git a/src/app/calculators/pab/pab.config.json b/src/app/calculators/pab/pab.config.json
index 443720b8d..197b72eba 100644
--- a/src/app/calculators/pab/pab.config.json
+++ b/src/app/calculators/pab/pab.config.json
@@ -24,46 +24,7 @@
         ]
     },
     {
-        "id": "fs_bassin",
-        "type": "fieldset_template",
-        "calcType": "PabCloisons",
-        "option": "fix",
-        "fields": [
-            {
-                "id": "select_modele_cloisons",
-                "type": "select_cloisons",
-                "select": []
-            },
-            {
-                "type": "input",
-                "id": "QA",
-                "unit": "m³/s"
-            }
-        ]
-    },
-    {
-        "id": "bassin_container",
-        "type": "template_container",
-        "templates": [
-            "fs_bassin"
-        ]
-    },
-    {
-        "id": "fs_cloison_aval",
-        "type": "fieldset",
-        "calcType": "Pab",
-        "fields": [
-            {
-                "id": "select_modele_cloison_aval",
-                "type": "select_cloison_aval",
-                "select": []
-            }
-        ]
-    },
-    {
-        "type": "options",
-        "modeleCloisonsSelectId": "select_modele_cloisons",
-        "modeleCloisonAvalSelectId": "select_modele_cloison_aval",
-        "idCal": "Q"
+        "id": "tableau_de_la_mort",
+        "type": "pab_table"
     }
-]
\ No newline at end of file
+]
diff --git a/src/app/components/field-set/field-set.component.ts b/src/app/components/field-set/field-set.component.ts
index ee5e3de85..16fa303ad 100644
--- a/src/app/components/field-set/field-set.component.ts
+++ b/src/app/components/field-set/field-set.component.ts
@@ -211,15 +211,17 @@ export class FieldSetComponent implements DoCheck {
      * détermine si un Field est du type SelectFieldModel
      */
     private isSelectModelField(f: Field): boolean {
-        return (
+        /* return (
             f instanceof SelectFieldModel
             && f.parentForm instanceof FormulairePab
             && (
                 f.id === (f.parentForm as FormulairePab).modeleCloisonsSelectId
                 || f.id === (f.parentForm as FormulairePab).modeleCloisonAvalSelectId
             )
-        );
+        ); */
+        return false; // tmp patch
     }
+
     /*
      * gestion des événements clic sur les radios :
      * réception d'un message du composant enfant (param-field)
diff --git a/src/app/components/generic-calculator/calculator.component.html b/src/app/components/generic-calculator/calculator.component.html
index 7356b4b5a..72238c220 100644
--- a/src/app/components/generic-calculator/calculator.component.html
+++ b/src/app/components/generic-calculator/calculator.component.html
@@ -39,14 +39,18 @@
 
                     <ng-template ngFor let-fe [ngForOf]="formElements">
                         <field-set *ngIf="isFieldset(fe)" [style.display]="getFieldsetStyleDisplay(fe.id)" [fieldSet]=fe
-                            (radio)=onRadioClick($event) (validChange)=OnFieldsetValid() (inputChange)=onInputChange($event)
+                            (radio)=onRadioClick($event) (validChange)=onElementValid() (inputChange)=onInputChange($event)
                             (tabPressed)="onTabPressed($event)">
                         </field-set>
 
                         <fieldset-container *ngIf="isFieldsetContainer(fe)" [_container]=fe (radio)=onRadioClick($event)
-                            (validChange)=onFieldsetContainerValid() (inputChange)=onInputChange($event)
+                            (validChange)=onElementValid() (inputChange)=onInputChange($event)
                             (tabPressed)="onTabPressed($event)">
                         </fieldset-container>
+
+                        <pab-table *ngIf="isPabTable(fe)" [pabTable]=fe (radio)=onRadioClick($event)
+                            (validChange)=onElementValid() (inputChange)=onInputChange($event)>
+                        </pab-table>
                     </ng-template>
 
                     <mat-card-actions>
diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts
index a83ea6303..3b65cc69b 100644
--- a/src/app/components/generic-calculator/calculator.component.ts
+++ b/src/app/components/generic-calculator/calculator.component.ts
@@ -21,6 +21,7 @@ import { MatDialog } from "@angular/material";
 import { DialogConfirmCloseCalcComponent } from "../dialog-confirm-close-calc/dialog-confirm-close-calc.component";
 import { DialogGeneratePABComponent } from "../dialog-generate-pab/dialog-generate-pab.component";
 import { SelectFieldModel } from "../../formulaire/select-field-model";
+import { PabTable } from "../../formulaire/pab-table";
 
 @Component({
     selector: "hydrocalc",
@@ -131,6 +132,13 @@ export class GenericCalculatorComponent extends BaseComponent implements OnInit,
         return fe instanceof FieldsetContainer;
     }
 
+    /**
+     * détermine si un FormulaireElement est du type PabTable
+     */
+    public isPabTable(fe: any): boolean {
+        return fe instanceof PabTable;
+    }
+
     public get hasForm() {
         return this._formulaire !== undefined;
     }
@@ -354,16 +362,9 @@ export class GenericCalculatorComponent extends BaseComponent implements OnInit,
     }
 
     /**
-     * réception d'un événement de validité d'un FieldSetComponent
-     */
-    public OnFieldsetValid() {
-        this.updateUIValidity();
-    }
-
-    /**
-     * réception d'un événement de validité d'un FieldsetContainerComponent
+     * réception d'un événement de validité d'un FormElement
      */
-    public onFieldsetContainerValid() {
+    public onElementValid() {
         this.updateUIValidity();
     }
 
diff --git a/src/app/components/pab-table/pab-table.component.html b/src/app/components/pab-table/pab-table.component.html
new file mode 100644
index 000000000..7eba1ea01
--- /dev/null
+++ b/src/app/components/pab-table/pab-table.component.html
@@ -0,0 +1,15 @@
+<mat-card-header class="bg-accent-light">
+    <mat-card-title>
+        {{ title }}
+    </mat-card-title>
+</mat-card-header>
+
+<mat-card-content>
+    Ici le tableau méga guedin !
+    <!-- <field-set *ngFor="let fs of fieldsets" class="fieldset-inner" [fieldSet]=fs
+        (radio)=onRadioClick($event) (validChange)=onFieldsetValid() (inputChange)=onInputChange($event)
+        (addFieldset)=onAddFieldset($event) (removeFieldset)=onRemoveFieldset($event)
+        (moveFieldsetDown)=onMoveFieldsetDown($event) (moveFieldsetUp)=onMoveFieldsetUp($event)
+        (tabPressed)="onTabPressed($event)">
+    </field-set> -->
+</mat-card-content>
diff --git a/src/app/components/pab-table/pab-table.component.scss b/src/app/components/pab-table/pab-table.component.scss
new file mode 100644
index 000000000..fcc76e896
--- /dev/null
+++ b/src/app/components/pab-table/pab-table.component.scss
@@ -0,0 +1,25 @@
+:host {
+    display: block;
+    // reduce margins to avoid inner field-sets being too narrow on 360px display
+    margin-left: -8px;
+    margin-right: -8px;
+}
+
+mat-card-header {
+    margin-left: -8px;
+    margin-right: -8px;
+    padding-left: 16px;
+    padding-top: 8px;
+    color: white;
+
+    // Pourquoi n'est-ce pas hérité de calculator.component.scss ?
+    // À cause de la surcharge de mat-card-header ci-dessus ?
+    mat-card-title {
+        font-size: 16px;
+        margin-bottom: 8px;
+    }
+}
+
+mat-card-content {
+    margin-top: 1em;
+}
diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts
new file mode 100644
index 000000000..695c33fc3
--- /dev/null
+++ b/src/app/components/pab-table/pab-table.component.ts
@@ -0,0 +1,153 @@
+import { Component, Input, Output, EventEmitter, QueryList, ViewChildren, DoCheck, AfterViewInit } from "@angular/core";
+
+import { FieldSetComponent } from "../field-set/field-set.component";
+import { I18nService } from "../../services/internationalisation/internationalisation.service";
+import { PabTable } from "../../formulaire/pab-table";
+
+/**
+ * The big editable data grid for calculator type "Pab" (component)
+ */
+@Component({
+    selector: "pab-table",
+    templateUrl: "./pab-table.component.html",
+    styleUrls: [
+        "./pab-table.component.scss"
+    ]
+})
+export class PabTableComponent implements DoCheck, AfterViewInit {
+
+    @Input()
+    private pabTable: PabTable;
+
+    /**
+     * liste des composants FieldSet enfants
+     */
+    @ViewChildren(FieldSetComponent)
+    private _fieldsetComponents: QueryList<FieldSetComponent>;
+
+    /**
+     * flag de validité des FieldSet enfants
+     */
+    private _isValid = false;
+
+    /**
+     * événément de changement d'état d'un radio
+     */
+    // tslint:disable-next-line:no-output-on-prefix
+    @Output()
+    private radio = new EventEmitter<any>();
+
+    /**
+     * événément de changement de validité
+     */
+    @Output()
+    private validChange = new EventEmitter();
+
+    /**
+     * événément de changement de valeur d'un input
+     */
+    @Output()
+    private inputChange = new EventEmitter();
+
+    /** événement signalant un appui sur TAB ou SHIFT+TAB */
+    @Output()
+    protected tabPressed = new EventEmitter<any>();
+
+    public constructor(
+        private i18nService: I18nService
+    ) { }
+
+    public get title(): string {
+        return this.i18nService.localizeText("INFO_PAB_TABLE");
+    }
+
+    public get isValid() {
+        return this._isValid;
+    }
+
+    /**
+     * Ajoute un nouveau sous-nub (Structure, PabCloisons selon le cas)
+     * dans un nouveau fieldset
+     */
+    /* private addSubNub(after?: FieldSet, clone: boolean = false) {
+        if (after) {
+            const newFs = this._container.addFromTemplate(0, after.indexAsKid());
+            if (clone) {
+                // replace in-place to change properties (overkill)
+                newFs.setPropValue("structureType", after.properties.getPropValue("structureType"));
+                newFs.setPropValue("loiDebit", after.properties.getPropValue("loiDebit"));
+                // after.nub.properties
+                for (const p of after.nub.prms) {
+                    newFs.nub.getParameter(p.symbol).singleValue = p.singleValue;
+                }
+            }
+        } else {
+            this._container.addFromTemplate(0);
+        }
+    } */
+
+    public ngAfterViewInit() {
+        /* this.onFieldsetListChange();
+        this._fieldsetComponents.changes.subscribe(_ => this.onFieldsetListChange()); */
+    }
+
+    public ngDoCheck() {
+        this.updateValidity();
+    }
+
+    /**
+    * calcul de la validité de tous les FieldSet de la vue
+    */
+    private updateValidity() {
+        this._isValid = false;
+
+        /* if (this._fieldsetComponents !== undefined) {
+            this._isValid = this._fieldsetComponents.reduce(
+                // callback
+                (
+                    // accumulator (valeur précédente du résultat)
+                    acc,
+                    // currentValue (élément courant dans le tableau)
+                    fieldset,
+                    // currentIndex (indice courant dans le tableau)
+                    currIndex,
+                    // array (tableau parcouru)
+                    array
+                ) => {
+                    return acc && fieldset.isValid;
+                }
+                // valeur initiale
+                , this._fieldsetComponents.length > 0);
+        } */
+
+        this.validChange.emit();
+    }
+
+    /**
+    * réception d'un événement de changement de valeur d'un input
+    */
+    private onInputChange($event) {
+        this.inputChange.emit($event);
+    }
+
+    /**
+     * relit les valeurs dans l'interface et met à jour les NgParameter
+     */
+    public updateParametersFromUI() {
+        this._fieldsetComponents.forEach(fsc => fsc.updateParametersFromUI());
+    }
+
+    /**
+     * met à jour les paramètres liés
+     */
+    public updateLinkedParameters() {
+        this._fieldsetComponents.forEach(fsc => fsc.updateLinkedParameters());
+    }
+
+    /**
+     * Renvoie l'événement au composant du dessus
+     */
+    public onTabPressed(event) {
+        console.log("tab pressed dans le tablo !");
+    }
+}
diff --git a/src/app/formulaire/definition/concrete/form-pab.ts b/src/app/formulaire/definition/concrete/form-pab.ts
index 18b63e068..c8dce277d 100644
--- a/src/app/formulaire/definition/concrete/form-pab.ts
+++ b/src/app/formulaire/definition/concrete/form-pab.ts
@@ -1,11 +1,11 @@
-import { Nub, Props, Session, PabCloisons, Pab } from "jalhyd";
+import { /* Nub, Props, Session, PabCloisons, */ Pab } from "jalhyd";
 
-import { FieldsetContainer } from "../../fieldset-container";
+/* import { FieldsetContainer } from "../../fieldset-container";
 import { FieldSet } from "../../fieldset";
 import { SelectField } from "../../select-field";
 import { NgParameter } from "../../ngparam";
 import { FieldsetTemplate } from "../../fieldset-template";
-import { FormulaireNode } from "../../formulaire-node";
+import { FormulaireNode } from "../../formulaire-node"; */
 import { FormulaireBase } from "./form-base";
 import { FormComputePab } from "../form-compute-pab";
 import { FormResultPab } from "../form-result-pab";
@@ -17,10 +17,10 @@ import { FormResultPab } from "../form-result-pab";
 export class FormulairePab extends FormulaireBase {
 
     /** id du select configurant le modèle de cloisons */
-    private _modeleCloisonsSelectId: string;
+    // private _modeleCloisonsSelectId: string;
 
     /** id du select configurant le modèle de la cloison aval */
-    private _modeleCloisonAvalSelectId: string;
+    // private _modeleCloisonAvalSelectId: string;
 
     constructor() {
         super();
@@ -31,71 +31,70 @@ export class FormulairePab extends FormulaireBase {
         this._formCompute = new FormComputePab(this, (this._formResult as FormResultPab));
     }
 
-    public get modeleCloisonsSelectId(): string {
+    private get pabNub(): Pab {
+        return this.currentNub as Pab;
+    }
+
+    public doCompute() {
+        this.dumpPabStructure(this.pabNub);
+        super.doCompute();
+    }
+
+    /* public get modeleCloisonsSelectId(): string {
         return this._modeleCloisonsSelectId;
     }
 
     public get modeleCloisonAvalSelectId(): string {
         return this._modeleCloisonAvalSelectId;
-    }
+    } */
 
     /**
      * Creates a virgin PabCloisons when a new fieldset is added through the GUI,
      * to ensure consistency; this object is not related to any Cloisons
      */
-    private createDummyPabCloisons(templ: FieldsetTemplate): Nub {
+    /* private createDummyPabCloisons(templ: FieldsetTemplate): Nub {
         const params = {};
         params["calcType"] = templ.calcTypeFromConfig;
         return this.createBassin(new Props(params));
-    }
+    } */
 
     /**
      * ajoute un Nub PabCloisons
      * @param after position après laquelle insérer la structure, à la fin sinon
      */
-    private addPabCloisons(st: PabCloisons, after?: number) {
+    /* private addPabCloisons(st: PabCloisons, after?: number) {
         this.pabNub.addChild(st, after);
-    }
-
-    private get pabNub(): Pab {
-        return this.currentNub as Pab;
-    }
+    } */
 
     /**
      * Asks JaLHyd to create a PabCloisons Nub as a child of the current Calculator Module
      * and return it; does not store it in the Session (for PabCloisons, not for Calculator Modules)
      * @param p properties for the new Nub
      */
-    protected createBassin(p: Props): PabCloisons {
+    /* protected createBassin(p: Props): PabCloisons {
         return Session.getInstance().createNub(p, this.currentNub as Pab) as PabCloisons;
-    }
+    } */
 
     /**
      * Replaces the current Nub in the current calculator module, with a new one built with properties "params"
      * @param params properties to build the new Nub (calcType, loiDebit...)
      */
-    protected replaceNub(sn: PabCloisons, params: Props): Nub {
+    /* protected replaceNub(sn: PabCloisons, params: Props): Nub {
         const parent = (this.currentNub as Pab);
         const newBassin = this.createBassin(params);
         parent.replaceChildInplace(sn, newBassin);
         return newBassin;
-    }
+    } */
 
     /**
      * Deleted the given child Nub in the current calculator module
      * @param params properties to build the new Nub (calcType, loiDebit...)
      */
-    protected deleteNub(sn: PabCloisons) {
+    /* protected deleteNub(sn: PabCloisons) {
         const parent = (this.currentNub as PabCloisons);
         parent.deleteChild(parent.getIndexForChild(sn));
-    }
-
-    public doCompute() {
-        this.dumpPabStructure(this.pabNub);
-        super.doCompute();
-    }
-
-    public createFieldset(parent: FormulaireNode, json: {}, data?: {}, nub?: Nub): FieldSet {
+    } */
+    /* public createFieldset(parent: FormulaireNode, json: {}, data?: {}, nub?: Nub): FieldSet {
         if (json["calcType"] === "PabCloisons") {
             // indice après lequel insérer le nouveau FieldSet
             const after = data["after"];
@@ -122,17 +121,17 @@ export class FormulairePab extends FormulaireBase {
         } else {
             return super.createFieldset(parent, json, data);
         }
-    }
+    } */
 
-    protected parseOptions(json: {}) {
+    /* protected parseOptions(json: {}) {
         super.parseOptions(json);
         // id du select configurant les modèles de cloisons
         this._modeleCloisonsSelectId = this.getOption(json, "modeleCloisonsSelectId");
         // id du select configurant le modèle de cloison aval
         this._modeleCloisonAvalSelectId = this.getOption(json, "modeleCloisonAvalSelectId");
-    }
+    } */
 
-    public afterParseFieldset(fs: FieldSet) {
+    /* public afterParseFieldset(fs: FieldSet) {
         // si le FieldSet contient le select de modèles de cloisons
         if (this._modeleCloisonsSelectId) {
             const node = fs.getFormulaireNodeById(this._modeleCloisonsSelectId);
@@ -151,81 +150,41 @@ export class FormulairePab extends FormulaireBase {
                 fs.properties.addObserver(this);
             }
         }
-    }
-
-    public moveFieldsetUp(fs: FieldSet) {
-        if (fs.nub instanceof PabCloisons) {
-            // déplacement du nub
-            fs.nub.parent.moveChildUp(fs.nub);
-            // déplacement du fieldset
-            this.fieldsetContainer.moveFieldsetUp(fs);
-
-            this.resetResults();
-        } else {
-            super.moveFieldsetUp(fs);
-        }
-    }
-
-    public moveFieldsetDown(fs: FieldSet) {
-        if (fs.nub instanceof PabCloisons) {
-            // déplacement du nub
-            fs.nub.parent.moveChildDown(fs.nub);
-            // déplacement du fieldset
-            this.fieldsetContainer.moveFieldsetDown(fs);
-
-            this.resetResults();
-        } else {
-            super.moveFieldsetDown(fs);
-        }
-    }
+    } */
 
-    public removeFieldset(fs: FieldSet) {
-        if (fs.nub instanceof PabCloisons) {
-            // suppression du sous-nub dans le Nub parent
-            this.deleteNub(fs.nub);
-
-            // suppression du fieldset
-            this.fieldsetContainer.removeFieldset(fs);
-
-            this.resetResults();
-        } else {
-            super.removeFieldset(fs);
-        }
-    }
-
-    protected completeParse(json: {}) {
+    /* protected completeParse(json: {}) {
         this.subscribeFieldsetContainer();
-    }
+    } */
 
-    private get fieldsetContainer(): FieldsetContainer {
+    /* private get fieldsetContainer(): FieldsetContainer {
         const n = this.getFormulaireNodeById("bassin_container");
         if (n === undefined || !(n instanceof FieldsetContainer)) {
             throw new Error("l'élément 'bassin_container' n'est pas du type FieldsetContainer");
         }
         return n as FieldsetContainer;
-    }
+    } */
 
     /**
      * abonnement en tant qu'observateur du FieldsetContainer
      */
-    private subscribeFieldsetContainer() {
+    /* private subscribeFieldsetContainer() {
         this.fieldsetContainer.addObserver(this);
-    }
+    } */
 
     /**
      * abonnement en tant qu'observateur des NgParameter des FieldSet contenus dans le FieldsetContainer
      */
-    private subscribeBasinFields(fs: FieldSet) {
+    /* private subscribeBasinFields(fs: FieldSet) {
         for (const n of fs.allFormElements) {
             if (n instanceof NgParameter || n instanceof SelectField) {
                 n.addObserver(this);
             }
         }
-    }
+    } */
 
     // interface Observer
 
-    public update(sender: any, data: any) {
+    /* public update(sender: any, data: any) {
 
         super.update(sender, data);
 
@@ -266,12 +225,12 @@ export class FormulairePab extends FormulaireBase {
                     break;
             }
         }
-    }
+    } */
 
     // debug method
     private dumpPabStructure(pab: Pab) {
         console.log(`PAB: ${pab.uid}, ${pab.children.length} children`);
-        for (const c of pab.children) {
+        /* for (const c of pab.children) {
             console.log(
                 ` * child: ${c.uid}, based on ${c.properties.getPropValue("modeleCloisons")}`
                 + ` (cote amont ${c.prms.Z1.singleValue}, longueur ${c.prms.LB.singleValue})`
@@ -279,6 +238,6 @@ export class FormulairePab extends FormulaireBase {
         }
         if (pab.downWall) {
             console.log(`+ downstream wall: ${pab.downWall.uid}`);
-        }
+        } */
     }
 }
diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts
index 859cad4fb..6569081e7 100644
--- a/src/app/formulaire/definition/form-definition.ts
+++ b/src/app/formulaire/definition/form-definition.ts
@@ -13,6 +13,7 @@ import { DeepFormulaireElementIterator } from "../form-iterator/deep-element-ite
 import { TopFormulaireElementIterator } from "../form-iterator/top-element-iterator";
 import { CalculatorResults } from "../../results/calculator-results";
 import { ServiceFactory } from "../../services/service-factory";
+import { PabTable } from "../pab-table";
 
 /**
  * classe de base pour tous les formulaires
@@ -187,6 +188,12 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
         this.kids.push(fsc);
     }
 
+    private parse_pab_table(json: {}) {
+        const tab: PabTable = new PabTable(this);
+        tab.parseConfig(json);
+        this.kids.push(tab);
+    }
+
     public parseDependencies(json: {}) {
         // tslint:disable-next-line:forin
         for (const conf_index in json) {
@@ -271,6 +278,10 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs
                     this.parse_template_container(conf, templates);
                     break;
 
+                case "pab_table": // not generic at all
+                    this.parse_pab_table(conf);
+                    break;
+
                 default:
                     throw new Error(`type d'objet de module de calcul ${type} non pris en charge`);
             }
diff --git a/src/app/formulaire/pab-table.ts b/src/app/formulaire/pab-table.ts
new file mode 100644
index 000000000..1591b4a18
--- /dev/null
+++ b/src/app/formulaire/pab-table.ts
@@ -0,0 +1,18 @@
+import { FormulaireElement } from "./formulaire-element";
+import { FormulaireNode } from "./formulaire-node";
+
+/**
+ * The big editable data grid for calculator type "Pab" (model)
+ */
+export class PabTable extends FormulaireElement {
+
+    constructor(parent: FormulaireNode) {
+        super(parent);
+    }
+
+    public parseDependencies(json: {}) { } // implements abstract method of FormulaireNode
+
+    public parseConfig(json: {}) {
+        this._confId = json["id"];
+    }
+}
diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json
index 18aff4ce8..88bc01abe 100644
--- a/src/locale/messages.en.json
+++ b/src/locale/messages.en.json
@@ -195,6 +195,7 @@
     "INFO_OUVRAGE": "Structure",
     "INFO_PAB_TITRE_COURT": "Fish ladder",
     "INFO_PAB_TITRE": "Fish ladder",
+    "INFO_PAB_TABLE": "Fish ladder geometry",
     "INFO_PABCHUTE_TITRE_COURT": "FL: fall",
     "INFO_PABCHUTE_TITRE": "Fish ladder: fall",
     "INFO_PABDIMENSIONS_TITRE_COURT": "FL: dimensions",
diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json
index 1f1db9001..9e7f4dd5c 100644
--- a/src/locale/messages.fr.json
+++ b/src/locale/messages.fr.json
@@ -195,6 +195,7 @@
     "INFO_OUVRAGE": "Ouvrage",
     "INFO_PAB_TITRE_COURT": "PAB",
     "INFO_PAB_TITRE": "Passe à bassins",
+    "INFO_PAB_TABLE": "Géométrie de la passe",
     "INFO_PABCHUTE_TITRE_COURT": "PAB&nbsp;: chute",
     "INFO_PABCHUTE_TITRE": "Passe à bassins&nbsp;: chute",
     "INFO_PABDIMENSIONS_TITRE_COURT": "PAB&nbsp;: dimensions",
-- 
GitLab