From 8f7fde147a1ae87f716e218dc0cf447d0f4d3f3c Mon Sep 17 00:00:00 2001 From: "mathias.chouet" <mathias.chouet@irstea.fr> Date: Mon, 9 Sep 2019 10:53:21 +0200 Subject: [PATCH] Fix #283 - memorize quicknav position --- src/app/app.component.html | 4 +- src/app/app.component.ts | 61 ++++++++++++++++--- .../calculator.component.ts | 12 ++-- .../components/quicknav/quicknav.component.ts | 21 +++---- 4 files changed, 70 insertions(+), 28 deletions(-) diff --git a/src/app/app.component.html b/src/app/app.component.html index 06cd26748..85d1c1b96 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -43,8 +43,8 @@ <div cdkDropList cdkDropListOrientation="horizontal" (cdkDropListDropped)="dropCalcButton($event)"> <button mat-raised-button color="primary" *ngFor="let c of calculators" class="" [title]="c.title" - [routerLink]="['/calculator/',c.uid]" [color]="c.active ? '' : 'primary'" - (click)="setActiveCalc(c.uid)" (mouseup)="onMouseUp($event, c.uid)" + [color]="c.active ? '' : 'primary'" + (click)="toCalc(c.uid)" (mouseup)="onMouseUp($event, c.uid)" [ngClass]="['calculator-button', 'calculator-uid-' + c.uid, c.active ? 'active' : '' ]" cdkDragLockAxis="x" cdkDrag> diff --git a/src/app/app.component.ts b/src/app/app.component.ts index abe5222f9..428e6f13a 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,4 +1,4 @@ -import { Component, ApplicationRef, OnInit, OnDestroy, HostListener, ViewChild, ComponentRef } from "@angular/core"; +import { Component, OnInit, OnDestroy, HostListener, ViewChild } from "@angular/core"; import { Router, Event, NavigationEnd, ActivationEnd, NavigationStart, NavigationCancel, NavigationError } from "@angular/router"; import { MatDialog } from "@angular/material/dialog"; import { MatSidenav } from "@angular/material/sidenav"; @@ -21,6 +21,7 @@ import { DialogConfirmCloseCalcComponent } from "./components/dialog-confirm-clo import { DialogConfirmEmptySessionComponent } from "./components/dialog-confirm-empty-session/dialog-confirm-empty-session.component"; import { DialogLoadSessionComponent } from "./components/dialog-load-session/dialog-load-session.component"; import { DialogSaveSessionComponent } from "./components/dialog-save-session/dialog-save-session.component"; +import { QuicknavComponent } from "./components/quicknav/quicknav.component"; import { NotificationsService } from "./services/notifications/notifications.service"; import { HotkeysService, Hotkey } from "angular2-hotkeys"; @@ -53,13 +54,14 @@ export class AppComponent implements OnInit, OnDestroy, Observer { /** progress bar percentage, for "determinate" mode */ public progessBarValue = 0; - /** - * liste des modules de calcul. Forme des objets : - * "title": nom du module de calcul - * "type": calcType du Nub associé - * "uid": id unique du formulaire - */ - private _calculators: any[] = []; + /** liste des modules de calcul ouverts */ + private _calculators: Array<{ + title: string, + type: CalculatorType, + uid: string, + active?: boolean, + latestAnchor?: string + }> = []; /** * id du formulaire courant @@ -451,6 +453,9 @@ export class AppComponent implements OnInit, OnDestroy, Observer { public toCalc(id: string) { this.router.navigate(["/calculator", id]); this.setActiveCalc(id); + setTimeout(() => { // @WARNING clodo trick to wait for Angular refresh + this.scrollToLatestQuicknav(id); + }, 50); } /** @@ -618,6 +623,46 @@ export class AppComponent implements OnInit, OnDestroy, Observer { }); } + /** + * Moves the view to one of the Quicknav anchors in the page, and saves this anchor + * as the latest visited, in _calculators list + * @param itemId a Quicknav anchor id (ex: "input" or "results") + */ + public scrollToQuicknav(itemId: string, behavior: ScrollBehavior = "smooth") { + const idx = this.getCalculatorIndexFromId(this.currentFormId); + if (idx > -1) { + const id = QuicknavComponent.prefix + itemId; + // Scroll https://stackoverflow.com/a/56391657/5986614 + const element = document.getElementById(id); + if (element && element.offsetParent !== null) { // offsetParent is null when element is not visible + const yCoordinate = element.getBoundingClientRect().top + window.pageYOffset; + window.scrollTo({ + top: yCoordinate - 60, // substract a little more than navbar height + behavior: behavior + }); + // Save position + this._calculators[idx].latestAnchor = itemId; + } else { + throw Error("scrollToQuicknav: cannot find anchor " + id); + } + } + } + + /** + * Moves the view to the latest known Quicknav anchor of the current module + */ + public scrollToLatestQuicknav(formId: string) { + // Get position + const idx = this.getCalculatorIndexFromId(formId); + if (idx > -1) { + const itemId = this._calculators[idx].latestAnchor; + // Scroll + if (itemId) { + this.scrollToQuicknav(itemId, "auto"); + } + } + } + public dropCalcButton(event: CdkDragDrop<string[]>) { moveItemInArray(this.calculators, event.previousIndex, event.currentIndex); } diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts index 5db971646..5e1d144b1 100644 --- a/src/app/components/generic-calculator/calculator.component.ts +++ b/src/app/components/generic-calculator/calculator.component.ts @@ -306,10 +306,14 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe * Moves the view to the start of the "Results" section */ private scrollToResults() { - // @TODO try to scroll to quicknav "results" first - const element = document.getElementById ("fake-results-anchor"); - if (element) { - element.scrollIntoView(); + // try to scroll to quicknav "results" first + try { + this.appComponent.scrollToQuicknav("results"); + } catch (e) { + const element = document.getElementById ("fake-results-anchor"); + if (element) { + element.scrollIntoView(); + } } } diff --git a/src/app/components/quicknav/quicknav.component.ts b/src/app/components/quicknav/quicknav.component.ts index 17e442ef9..8770fb33f 100644 --- a/src/app/components/quicknav/quicknav.component.ts +++ b/src/app/components/quicknav/quicknav.component.ts @@ -1,6 +1,7 @@ -import { Component, Input } from "@angular/core"; +import { Component, Input, Inject, forwardRef } from "@angular/core"; import { I18nService } from "../../services/internationalisation/internationalisation.service"; +import { AppComponent } from "../../app.component"; @Component({ selector: "quicknav", @@ -11,6 +12,8 @@ import { I18nService } from "../../services/internationalisation/internationalis }) export class QuicknavComponent { + public static prefix = "qn_"; + @Input() public items: string[]; @@ -20,9 +23,8 @@ export class QuicknavComponent { @Input() public align: string; - private prefix = "qn_"; - public constructor( + @Inject(forwardRef(() => AppComponent)) private appComponent: AppComponent, private i18nService: I18nService ) { this.items = []; @@ -31,7 +33,7 @@ export class QuicknavComponent { } public get id() { - return this.prefix + this.currentItem; + return QuicknavComponent.prefix + this.currentItem; } public get hasItems() { @@ -53,15 +55,6 @@ export class QuicknavComponent { } public scrollTo(item: string) { - // https://stackoverflow.com/a/56391657/5986614 - const element = document.getElementById(this.prefix + item); - if (element) { - const yCoordinate = element.getBoundingClientRect().top + window.pageYOffset; - // element.scrollIntoView({behavior: "smooth", block: "start", inline: "nearest"}); - window.scrollTo({ - top: yCoordinate - 60, // substract a little more than navbar height - behavior: "smooth" - }); - } + this.appComponent.scrollToQuicknav(item); } } -- GitLab