diff --git a/jalhyd_branch b/jalhyd_branch index 6ba102133f195085ddf25826b3ac5dbc6162e06a..1f7391f92b6a3792204e07e99f71f643cc35e7e1 100644 --- a/jalhyd_branch +++ b/jalhyd_branch @@ -1 +1 @@ -54-ameliorer-le-filtre-de-choix-des-parametres-pouvant-etre-lies +master diff --git a/preprocessors.js b/preprocessors.js index ecc9953833312063a4e7cc40d45501c563218a1c..e95d481c3afaace51f8262ce13a5bed8f8e7e28d 100755 --- a/preprocessors.js +++ b/preprocessors.js @@ -7,13 +7,16 @@ var fs = require('fs'); date_last_commit = require('child_process') .execSync('git log -1 --format=%cd --date=short') .toString().trim() +version = require('child_process') + .execSync('git describe') + .toString().trim() var sFileName = "src/date_revision.ts"; -fs.writeFile(sFileName, `export const nghydDateRev = "${date_last_commit}";\n`, function(err) { +fs.writeFile(sFileName, `export const nghydDateRev = "${date_last_commit}";\nexport const nghydVersion = "${version}";\n`, function(err) { if(err) { return console.log(err); } - console.log(`File ${sFileName} saved with date ${date_last_commit}`); -}); \ No newline at end of file + console.log(`File ${sFileName} saved with date ${date_last_commit}, version ${version}`); +}); diff --git a/src/app/app.component.html b/src/app/app.component.html index 4ce195dc932e87b808a00f207ece07f32c081383..50dad1690423162f37f5f32cd42733eee20a5155 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -53,8 +53,7 @@ </div> <button mat-icon-button id="new-calculator" routerLink="/list" (click)="sidenav.close()"> - <mat-icon *ngIf="calculators.length > 0">add_box</mat-icon> - <mat-icon *ngIf="calculators.length === 0">home</mat-icon> + <mat-icon *ngIf="currentRoute != '/list'">add_box</mat-icon> </button> <div id="toolbar-bottom-spacer"></div> @@ -96,8 +95,18 @@ </a> <div class="hyd_version"> - JaLHyd version: {{ getDateRevision()[0] }}<br/> - ngHyd version: {{ getDateRevision()[1] }} + <div class="jalhyd-version"> + <span class="version"> + JaLHyd: <span class="value">{{ revisionInfo.jalhyd.version }}</span> + </span> + <span class="date">updated {{ revisionInfo.jalhyd.date }}</span> + </div> + <div class="nghyd-version"> + <span class="version"> + ngHyd: <span class="value">{{ revisionInfo.nghyd.version }}</span> + </span> + <span class="date">updated {{ revisionInfo.nghyd.date }}</span> + </div> </div> </div> </mat-sidenav> diff --git a/src/app/app.component.scss b/src/app/app.component.scss index 98e0c6c01190ec530e9de00bbd4607cee816e439..6cf6170efb960b768f974b26cd99fe23ac0220cd 100644 --- a/src/app/app.component.scss +++ b/src/app/app.component.scss @@ -216,6 +216,22 @@ button:focus { color: #888888; padding: 0 2em 1em 0; text-align: right; + + .jalhyd-version { + margin-bottom: 0.6em; + } + + .version { + display: block; + + > .value { + font-weight: bold; + } + } + + .date { + font-size: 0.8em; + } } .closebtn { diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 43e8c0f2cae73777a948eb1642331225313445bb..9f7ad4caf20241acc0c3e4e8fc250b15327bdbfb 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -3,7 +3,7 @@ import { Router, Event, NavigationEnd, ActivationEnd } from "@angular/router"; import { MatSidenav, MatToolbar, MatDialog, MatIconRegistry } from "@angular/material"; import { DomSanitizer } from "@angular/platform-browser"; -import { Observer, jalhydDateRev, CalculatorType, Session } from "jalhyd"; +import { Observer, jalhydDateRev, jalhydVersion, CalculatorType, Session } from "jalhyd"; import { environment } from "../environments/environment"; import { I18nService } from "./services/internationalisation/internationalisation.service"; @@ -13,7 +13,7 @@ import { FormulaireDefinition } from "./formulaire/definition/form-definition"; import { ServiceFactory } from "./services/service-factory"; import { HttpService } from "./services/http/http.service"; import { ApplicationSetupService } from "./services/app-setup/app-setup.service"; -import { nghydDateRev } from "../date_revision"; +import { nghydDateRev, nghydVersion } from "../date_revision"; import { DialogConfirmEmptySessionComponent } from "./components/dialog-confirm-empty-session/dialog-confirm-empty-session.component"; import { DialogLoadSessionComponent } from "./components/dialog-load-session/dialog-load-session.component"; @@ -172,6 +172,10 @@ export class AppComponent implements OnInit, OnDestroy, Observer { return this._currentFormId; } + public get currentRoute(): string { + return this.router.url; + } + public setActiveCalc(uid: string) { this._calculators.forEach((calc) => { calc.active = (calc.uid === uid); @@ -407,9 +411,17 @@ export class AppComponent implements OnInit, OnDestroy, Observer { }); } - public getDateRevision(): string[] { - const dr: string[] = [jalhydDateRev, nghydDateRev]; - return dr; + public get revisionInfo(): any { + return { + jalhyd: { + date: jalhydDateRev, + version: jalhydVersion, + }, + nghyd: { + date: nghydDateRev, + version: nghydVersion + } + }; } /** diff --git a/src/app/components/field-set/field-set.component.html b/src/app/components/field-set/field-set.component.html index b87bbe724705e0503c85490c8e4cbdabb19188d8..0dea7034b85852407812e4aea01b96e592239fc6 100644 --- a/src/app/components/field-set/field-set.component.html +++ b/src/app/components/field-set/field-set.component.html @@ -20,7 +20,8 @@ <mat-card-content> <ng-template ngFor let-p [ngForOf]="fields"> - <param-field-line *ngIf="isInputField(p)" [param]=p (radio)=onRadioClick($event) (valid)=onParamLineValid() (inputChange)=onInputChange()> + <param-field-line *ngIf="isInputField(p)" [param]=p (radio)=onRadioClick($event) (valid)=onParamLineValid() + (inputChange)=onInputChange() (tabPressed)="onTabPressed($event)"> </param-field-line> <select-field-line *ngIf="isSelectField(p)" [_select]=p> diff --git a/src/app/components/field-set/field-set.component.ts b/src/app/components/field-set/field-set.component.ts index 1541cba64a890778294eeaa5309ece21a2204796..bb3c51de86b46f5a931fee54cf659e553c1b8fa4 100644 --- a/src/app/components/field-set/field-set.component.ts +++ b/src/app/components/field-set/field-set.component.ts @@ -117,6 +117,10 @@ export class FieldSetComponent implements DoCheck { @Output() private radio = new EventEmitter<any>(); + /** événement signalant un appui sur TAB ou SHIFT+TAB */ + @Output() + protected tabPressed = new EventEmitter<any>(); + private hasRadioFix(): boolean { if (this._fieldSet.hasInputs) { switch (this._fieldSet.getInput(0).radioConfig) { @@ -209,6 +213,13 @@ export class FieldSetComponent implements DoCheck { this.validChange.emit(); } + /** + * Renvoie l'événement au composant du dessus + */ + public onTabPressed(event) { + this.tabPressed.emit(event); + } + public ngDoCheck() { this.updateValidity(); } diff --git a/src/app/components/fieldset-container/fieldset-container.component.html b/src/app/components/fieldset-container/fieldset-container.component.html index 3bb2f5d4c370f52dd13b9ceabe74bea170bf0fe8..c2f75e4f19ef29b671ec12f24afabd08b67f648b 100644 --- a/src/app/components/fieldset-container/fieldset-container.component.html +++ b/src/app/components/fieldset-container/fieldset-container.component.html @@ -8,6 +8,7 @@ <field-set *ngFor="let fs of fieldsets" class="fieldset-inner" [fieldSet]=fs (radio)=onRadioClick($event) (validChange)=onFieldsetValid() (inputChange)=onInputChange() (addFieldset)=onAddFieldset($event) (removeFieldset)=onRemoveFieldset($event) - (moveFieldsetDown)=onMoveFieldsetDown($event) (moveFieldsetUp)=onMoveFieldsetUp($event)> + (moveFieldsetDown)=onMoveFieldsetDown($event) (moveFieldsetUp)=onMoveFieldsetUp($event) + (tabPressed)="onTabPressed($event)"> </field-set> </mat-card-content> diff --git a/src/app/components/fieldset-container/fieldset-container.component.ts b/src/app/components/fieldset-container/fieldset-container.component.ts index 15ca4d3e33a0c30d819d8b731ed32d8d20ffec51..b5e7be12e51d7e97caa1ee80e71024378c4e9522 100644 --- a/src/app/components/fieldset-container/fieldset-container.component.ts +++ b/src/app/components/fieldset-container/fieldset-container.component.ts @@ -60,6 +60,10 @@ export class FieldsetContainerComponent implements DoCheck, AfterViewInit { @Output() private inputChange = new EventEmitter(); + /** événement signalant un appui sur TAB ou SHIFT+TAB */ + @Output() + protected tabPressed = new EventEmitter<any>(); + private addStructure(after?: FieldSet) { if (after) { this._container.addFromTemplate(0, after.indexAsKid()); @@ -204,4 +208,11 @@ export class FieldsetContainerComponent implements DoCheck, AfterViewInit { const form = this._container.parent as FormulaireDefinition; form.moveFieldsetDown(fs); } + + /** + * Renvoie l'événement au composant du dessus + */ + public onTabPressed(event) { + this.tabPressed.emit(event); + } } diff --git a/src/app/components/generic-calculator/calculator.component.html b/src/app/components/generic-calculator/calculator.component.html index a714e0be4ec9b5bac39a194d92fbecfded9932f2..27eb0116b79bdf0a9ae47fa11d3623aa758914f1 100644 --- a/src/app/components/generic-calculator/calculator.component.html +++ b/src/app/components/generic-calculator/calculator.component.html @@ -32,10 +32,14 @@ <!-- chapitres --> <mat-card id="calc-card-field-sets" fxFlex.gt-xs="1 0 400px" fxFlex.lt-sm="1 0 300px"> <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()></field-set> + <field-set *ngIf="isFieldset(fe)" [style.display]="getFieldsetStyleDisplay(fe.id)" [fieldSet]=fe + (radio)=onRadioClick($event) (validChange)=OnFieldsetValid() (inputChange)=onInputChange() + (tabPressed)="onTabPressed($event)"> + </field-set> - <fieldset-container *ngIf="isFieldsetContainer(fe)" [_container]=fe (radio)=onRadioClick($event) (validChange)=onFieldsetContainerValid()></fieldset-container> + <fieldset-container *ngIf="isFieldsetContainer(fe)" [_container]=fe (radio)=onRadioClick($event) + (validChange)=onFieldsetContainerValid() (tabPressed)="onTabPressed($event)"> + </fieldset-container> </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 31842b9690c9e477dfd037eebcbe24686421144d..d7a267bb7d34f8fc668b9263a7cfd371eccb717a 100644 --- a/src/app/components/generic-calculator/calculator.component.ts +++ b/src/app/components/generic-calculator/calculator.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, DoCheck, OnDestroy, ViewChild, ViewChildren, QueryList, AfterViewChecked } from "@angular/core"; +import { Component, OnInit, DoCheck, OnDestroy, ViewChild, ViewChildren, QueryList, AfterViewChecked, ElementRef, Renderer2 } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; import { Observer, Session, ParamValueMode } from "jalhyd"; @@ -98,7 +98,9 @@ export class GenericCalculatorComponent extends BaseComponent implements OnInit, constructor( private route: ActivatedRoute, private router: Router, - private confirmCloseCalcDialog: MatDialog + private confirmCloseCalcDialog: MatDialog, + private _elementRef: ElementRef, + private renderer: Renderer2 ) { super(); this.intlService = ServiceFactory.instance.i18nService; @@ -308,7 +310,11 @@ export class GenericCalculatorComponent extends BaseComponent implements OnInit, // accumulator (valeur précédente du résultat) acc, // currentValue (élément courant dans le tableau) - fieldset + fieldset, + // currentIndex (indice courant dans le tableau) + currIndex, + // array (tableau parcouru) + array ) => { return acc && fieldset.isValid; } @@ -322,7 +328,11 @@ export class GenericCalculatorComponent extends BaseComponent implements OnInit, // accumulator (valeur précédente du résultat) acc, // currentValue (élément courant dans le tableau) - fieldsetContainer + fieldsetContainer, + // currentIndex (indice courant dans le tableau) + currIndex, + // array (tableau parcouru) + array ) => { return acc && fieldsetContainer.isValid; } @@ -357,6 +367,43 @@ export class GenericCalculatorComponent extends BaseComponent implements OnInit, this._formulaire.resetResults([]); } + /** + * Passe d'un champ de saisie à l'autre lors de l'appui sur + * TAB, sans passer par les autres éléments d'interface + */ + public onTabPressed(event: any) { + // event source input id + const srcId = event.originalEvent.target.id; + + // find all available inputs + const qs = "ngparam-input input.form-control"; + let inputs: Node[] = Array.from(this._elementRef.nativeElement.querySelectorAll(qs)); + + // find calculated symbol if any, to exclude it from inputs list + let calcSymbol = ""; + if (this._formulaire.currentNub.calculatedParam) { + calcSymbol = this._formulaire.currentNub.calculatedParam.symbol; + } + inputs = inputs.filter((i: any) => { + return i.id !== calcSymbol; + }); + + // find position among inputs list + const currentIndex = inputs.findIndex((i: any) => { + return i.id === srcId; + }); + + // focus previous / next input + let newIndex = currentIndex; + if (event.shift) { + newIndex = (newIndex === 0) ? (inputs.length - 1) : (newIndex - 1); + } else { + newIndex = (newIndex + 1) % inputs.length; + } + const elt = (inputs[newIndex] as HTMLElement); + elt.focus(); + } + public openHelp() { window.open("assets/docs-fr/calculators/" + this._formulaire.helpLink + "/", "_blank"); } diff --git a/src/app/components/generic-input/generic-input.component.html b/src/app/components/generic-input/generic-input.component.html index f6ca6506f4d99ffcef937546366fca94cbcf63eb..c60194a79e28b460780eace9cbca97dc9caf8311 100644 --- a/src/app/components/generic-input/generic-input.component.html +++ b/src/app/components/generic-input/generic-input.component.html @@ -1,6 +1,7 @@ <mat-form-field> <input matInput #inputControl="ngModel" class="form-control" type="text" inputmode="numeric" [id]="inputId" [name]="inputId" [disabled]="isDisabled" [(ngModel)]="uiValue" [placeholder]="title" + (keydown.Tab)="onTabPressed($event, false)" (keydown.shift.Tab)="onTabPressed($event, true)" pattern="^-?([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$" required> <mat-error>{{ errorMessage }}</mat-error> diff --git a/src/app/components/generic-input/generic-input.component.ts b/src/app/components/generic-input/generic-input.component.ts index 1bac270188ab49a87be7951a421abad277d45947..e75f2ed188380b1ffebd83a96705e1fc6afd6a56 100644 --- a/src/app/components/generic-input/generic-input.component.ts +++ b/src/app/components/generic-input/generic-input.component.ts @@ -1,7 +1,7 @@ import { Input, Output, EventEmitter, ChangeDetectorRef, OnChanges, ViewChild } from "@angular/core"; import { NgModel } from "@angular/forms"; import { BaseComponent } from "../base/base.component"; -import { isNumeric } from "jalhyd"; +import { isNumeric, Structure } from "jalhyd"; import { FormulaireDefinition } from "../../formulaire/definition/form-definition"; import { NgParameter } from "../../formulaire/ngparam"; import { I18nService } from "../../services/internationalisation/internationalisation.service"; @@ -37,11 +37,18 @@ export abstract class GenericInputComponent extends BaseComponent implements OnC * id de l'input, utilisé notamment pour les tests */ public get inputId() { - let id = "input-1"; + let id = "error-in-inputId"; if (this._model) { // unique input id based on parameter symbol if (this._model instanceof NgParameter) { - id = (this._model as NgParameter).symbol; + const param = this._model as NgParameter; + id = param.symbol; + // if inside a nested Structure, prefix with Structure position + // to disambiguate + const nub = param.paramDefinition.parentNub; + if (nub && nub instanceof Structure) { + id = nub.findPositionInParent() + "_" + id; + } } } return id; @@ -59,6 +66,12 @@ export abstract class GenericInputComponent extends BaseComponent implements OnC @Output() protected change = new EventEmitter<any>(); + /** + * événement signalant un appui sur TAB ou SHIFT+TAB + */ + @Output() + protected tabPressed = new EventEmitter<any>(); + /** * valeur saisie. * Cette variable n'est modifiée que lorsqu'on affecte le modèle ou que l'utilisateur fait une saisie @@ -231,6 +244,14 @@ export abstract class GenericInputComponent extends BaseComponent implements OnC } } + /** + * Renvoie l'événement au composant du dessus + */ + public onTabPressed(event, shift: boolean) { + this.tabPressed.emit({ originalEvent: event, shift: shift }); + return false; // stops event propagation + } + private updateAll() { this.updateAndValidateUI(); this.validateModel(); diff --git a/src/app/components/param-field-line/param-field-line.component.html b/src/app/components/param-field-line/param-field-line.component.html index acea333d21ba24a32813148e8aa38eb7147670f6..1c71eb5b957985b949b08b7862ed29578c6bb4e1 100644 --- a/src/app/components/param-field-line/param-field-line.component.html +++ b/src/app/components/param-field-line/param-field-line.component.html @@ -4,7 +4,8 @@ <!-- input de saisie de la valeur --> <div fxFlex="1 0 120px"> <!-- composant pour gérer le cas général (valeur numérique à saisir) --> - <ngparam-input [title]="param.title" [hidden]="! isRadioFixChecked" (change)="onInputChange($event)"></ngparam-input> + <ngparam-input [title]="param.title" [hidden]="! isRadioFixChecked" + (change)="onInputChange($event)" (tabPressed)="onTabPressed($event)"></ngparam-input> <!-- composant pour gérer le cas "paramètre calculé" --> <param-computed *ngIf="isRadioCalChecked" [title]="title" [param]="param"></param-computed> diff --git a/src/app/components/param-field-line/param-field-line.component.ts b/src/app/components/param-field-line/param-field-line.component.ts index 06a78419f964544919d962f0dbe3c70903509b9d..59b38594abab5f9dd8da14bad4eef6d6afb0689e 100644 --- a/src/app/components/param-field-line/param-field-line.component.ts +++ b/src/app/components/param-field-line/param-field-line.component.ts @@ -127,6 +127,10 @@ export class ParamFieldLineComponent implements OnChanges { @Output() private inputChange: EventEmitter<void>; + /** événement signalant un appui sur TAB ou SHIFT+TAB */ + @Output() + protected tabPressed = new EventEmitter<any>(); + /** true si la valeur saisie est valide */ private _isInputValid = false; @@ -266,6 +270,13 @@ export class ParamFieldLineComponent implements OnChanges { this.emitValidity(); } + /** + * Renvoie l'événement au composant du dessus + */ + public onTabPressed(event) { + this.tabPressed.emit(event); + } + /** * émission d'un événement de validité */