changed description editor table of contents
This commit is contained in:
parent
8a8aa40ac9
commit
8940394aa5
|
@ -107,7 +107,7 @@
|
|||
<div class="row toc-pane-container" #boundary>
|
||||
<div #spacer></div>
|
||||
<div class="col-12">
|
||||
<app-table-of-contents [visibilityRulesService]="visibilityRulesService" [selectedFieldsetId]="fieldsetIdWithFocus" #table0fContents [showErrors]="showtocentriesErrors" [hasFocus]="step > 0" [formGroup]="formGroup.get('properties')" [descriptionTemplate]="item.descriptionTemplate" *ngIf="formGroup" [links]="links" [boundary]="boundary" [spacer]="spacer" [isActive]="step !== 0" stickyThing (stepFound)="onStepFound($event)" (currentLinks)="getLinks($event)" (entrySelected)="changeStep($event.entry, $event.execute)" [pageToFieldSetMap]="pageToFieldSetMap"></app-table-of-contents>
|
||||
<app-table-of-contents [visibilityRulesService]="visibilityRulesService" #table0fContents [showErrors]="showTocEntriesErrors" [hasFocus]="step > 0" [formGroup]="formGroup.get('properties')" [descriptionTemplate]="item.descriptionTemplate" *ngIf="formGroup" [links]="links" [boundary]="boundary" [spacer]="spacer" [isActive]="step !== 0" stickyThing (entrySelected)="changeStep($event.entry, $event.execute)" [pageToFieldSetMap]="pageToFieldSetMap"></app-table-of-contents>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -163,7 +163,6 @@
|
|||
[validationErrorModel]="editorModel.validationErrorModel"
|
||||
[isNew]="isNew || isCopy"
|
||||
[canReview]="canReview"
|
||||
(fieldsetFocusChange)="fieldsetIdWithFocus = $event"
|
||||
></app-description-form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -46,7 +46,7 @@ import { DescriptionEditorService } from './description-editor.service';
|
|||
import { PrefillDescriptionDialogComponent } from './prefill-description/prefill-description.component';
|
||||
import { ToCEntry } from './table-of-contents/models/toc-entry';
|
||||
import { ToCEntryType } from './table-of-contents/models/toc-entry-type.enum';
|
||||
import { TableOfContentsValidationService } from './table-of-contents/services/table-of-contents-validation-service';
|
||||
import { TableOfContentsService } from './table-of-contents/services/table-of-contents-service';
|
||||
import { TableOfContentsComponent } from './table-of-contents/table-of-contents.component';
|
||||
|
||||
@Component({
|
||||
|
@ -63,13 +63,13 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
canEdit = false;
|
||||
canReview = false;
|
||||
item: Description;
|
||||
fieldsetIdWithFocus: string;
|
||||
fileTransformerEntityTypeEnum = FileTransformerEntityType;
|
||||
|
||||
viewOnly = false;
|
||||
lockStatus: Boolean;
|
||||
descriptionIsOnceSaved = false;
|
||||
isFinalized = false;
|
||||
showTocEntriesErrors = false;
|
||||
@ViewChild('table0fContents') table0fContents: TableOfContentsComponent;
|
||||
step: number = 0;
|
||||
|
||||
|
@ -100,11 +100,10 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
private descriptionTemplateService: DescriptionTemplateService,
|
||||
public visibilityRulesService: VisibilityRulesService,
|
||||
public fileTransformerService: FileTransformerService,
|
||||
public tocValidationService: TableOfContentsValidationService,
|
||||
public titleService: Title,
|
||||
private analyticsService: AnalyticsService,
|
||||
private breadcrumbService: BreadcrumbService,
|
||||
private changeDetectorRef: ChangeDetectorRef
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private tableOfContentsService: TableOfContentsService
|
||||
) {
|
||||
const descriptionLabel: string = route.snapshot.data['entity']?.label;
|
||||
if (descriptionLabel) {
|
||||
|
@ -140,7 +139,7 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
if (itemId != null && newDmpId == null) {
|
||||
this.checkLock(this.item.id, LockTargetType.Description, 'DESCRIPTION-EDITOR.LOCKED-DIALOG.TITLE', 'DESCRIPTION-EDITOR.LOCKED-DIALOG.MESSAGE');
|
||||
|
||||
}
|
||||
}
|
||||
else if (dmpId != null && dmpSectionId != null) {
|
||||
this.isNew = true;
|
||||
const dialogRef = this.dialog.open(PrefillDescriptionDialogComponent, {
|
||||
|
@ -156,13 +155,13 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
dialogRef.afterClosed().subscribe((result: Description) => {
|
||||
if (result) {
|
||||
this.titleService.setTitle(result.label);
|
||||
|
||||
|
||||
result.dmp = this.item.dmp;
|
||||
result.dmpDescriptionTemplate = this.item.dmpDescriptionTemplate;
|
||||
|
||||
|
||||
const sectionId = this.item.dmpDescriptionTemplate.sectionId;
|
||||
result.dmpDescriptionTemplate = this.item.dmp.dmpDescriptionTemplates.find(x => x.sectionId == sectionId && x.descriptionTemplateGroupId == result.descriptionTemplate.groupId);
|
||||
|
||||
|
||||
this.prepareForm(result);
|
||||
this.changeDetectorRef.markForCheck();
|
||||
}
|
||||
|
@ -267,10 +266,9 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
}
|
||||
|
||||
refreshData(): void {
|
||||
this.getItem(this.editorModel.id, (data: Description) => {
|
||||
this.getItem(this.editorModel.id, (data: Description) => {
|
||||
this.prepareForm(data)
|
||||
});
|
||||
this.tocValidationService.validateForm();
|
||||
}
|
||||
|
||||
refreshOnNavigateToData(id?: Guid): void {
|
||||
|
@ -551,9 +549,13 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
public changeStep(selected: ToCEntry = null, execute: boolean = true) {
|
||||
if (execute) {
|
||||
if (selected) {
|
||||
let fieldSet = this.getFirstFieldSet(selected);
|
||||
let index = this.visibleFieldSets.findIndex(entry => entry.id === fieldSet.id);
|
||||
this.step = index + (selected.type === ToCEntryType.FieldSet ? 1 : 0.5);
|
||||
if (this.step == 0) {
|
||||
this.step = 1;
|
||||
}
|
||||
const element = document.getElementById(selected.id);
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
} else {
|
||||
this.step = 0;
|
||||
this.resetScroll();
|
||||
|
@ -561,54 +563,44 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
}
|
||||
}
|
||||
|
||||
getFirstFieldSet(entry: ToCEntry): ToCEntry {
|
||||
if (entry.type === ToCEntryType.FieldSet && !this.table0fContents.internalTable.hiddenEntries.find(hiddenEntry => hiddenEntry === entry.id.toString())) {
|
||||
return entry;
|
||||
} else {
|
||||
let subEntries = entry.subEntries.filter(subEntry => !this.table0fContents.internalTable.hiddenEntries.find(hiddenEntry => hiddenEntry === subEntry.id.toString()));
|
||||
if (subEntries.length > 0) {
|
||||
return this.getFirstFieldSet(subEntries[0]);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get maxStep() {
|
||||
return this.visibleFieldSets.length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public nextStep() {
|
||||
if (this.step < this.maxStep) {//view is changing
|
||||
this.step = Math.floor(this.step + 1);
|
||||
let entry = this.visibleFieldSets[this.step - 1];
|
||||
const targetElement = document.getElementById(entry.id);
|
||||
if (targetElement) {
|
||||
this.table0fContents.onToCentrySelected(entry, false);
|
||||
this.scroll(entry);
|
||||
} else {
|
||||
this.nextStep();
|
||||
}
|
||||
}
|
||||
this.tableOfContentsService.nextClicked();
|
||||
// if (this.step < this.maxStep) {//view is changing
|
||||
// this.step = Math.floor(this.step + 1);
|
||||
// let entry = this.visibleFieldSets[this.step - 1];
|
||||
// const targetElement = document.getElementById(entry.id);
|
||||
// if (targetElement) {
|
||||
// this.table0fContents.onToCentrySelected(entry, false);
|
||||
// this.scroll(entry);
|
||||
// } else {
|
||||
// this.nextStep();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
public previousStep() {
|
||||
if (this.step > 0) {
|
||||
this.step = Math.ceil(this.step - 1);
|
||||
if (this.step >= 1) {
|
||||
let entry = this.visibleFieldSets[this.step - 1];
|
||||
const targetElement = document.getElementById(entry.id);
|
||||
if (targetElement) {
|
||||
this.table0fContents.onToCentrySelected(entry, false);
|
||||
this.scroll(entry);
|
||||
} else {
|
||||
this.previousStep();
|
||||
}
|
||||
} else {
|
||||
this.table0fContents.onToCentrySelected(null, false);
|
||||
this.resetScroll();
|
||||
}
|
||||
}
|
||||
this.tableOfContentsService.nextClicked();
|
||||
|
||||
// if (this.step > 0) {
|
||||
// this.step = Math.ceil(this.step - 1);
|
||||
// if (this.step >= 1) {
|
||||
// let entry = this.visibleFieldSets[this.step - 1];
|
||||
// const targetElement = document.getElementById(entry.id);
|
||||
// if (targetElement) {
|
||||
// this.table0fContents.onToCentrySelected(entry, false);
|
||||
// this.scroll(entry);
|
||||
// } else {
|
||||
// this.previousStep();
|
||||
// }
|
||||
// } else {
|
||||
// this.table0fContents.onToCentrySelected(null, false);
|
||||
// this.resetScroll();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
private scroll(entry: ToCEntry) {
|
||||
|
@ -619,19 +611,6 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
document.getElementById('description-editor-form').scrollTop = 0;
|
||||
}
|
||||
|
||||
get visibleFieldSets(): ToCEntry[] {
|
||||
let fieldSets = [];
|
||||
let arrays = this.table0fContents ? this.table0fContents.tocentries.
|
||||
filter(entry => !this.table0fContents.internalTable.hiddenEntries.find(hiddenEntry => hiddenEntry === entry.id.toString())).map(entry => {
|
||||
return this.getEntryVisibleFieldSets(entry);
|
||||
})
|
||||
: [];
|
||||
arrays.forEach(array => {
|
||||
fieldSets = fieldSets.concat(array);
|
||||
});
|
||||
return fieldSets;
|
||||
}
|
||||
|
||||
get countErrorsOfBaseInfoPage(): number {
|
||||
if (this.formGroup == null) return 0;
|
||||
|
||||
|
@ -645,18 +624,6 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
return errorsCount;
|
||||
}
|
||||
|
||||
getEntryVisibleFieldSets(entry: ToCEntry): ToCEntry[] {
|
||||
let fieldSets = [];
|
||||
if (entry.type === ToCEntryType.FieldSet && !this.table0fContents.internalTable.hiddenEntries.find(hiddenEntry => hiddenEntry === entry.id.toString())) {
|
||||
fieldSets.push(entry);
|
||||
} else if (entry.type !== ToCEntryType.FieldSet) {
|
||||
entry.subEntries.forEach(subEntry => {
|
||||
fieldSets = fieldSets.concat(this.getEntryVisibleFieldSets(subEntry));
|
||||
});
|
||||
}
|
||||
return fieldSets;
|
||||
}
|
||||
|
||||
registerFormListeners() {
|
||||
|
||||
this.formGroup.get('descriptionTemplateId').valueChanges
|
||||
|
@ -667,35 +634,31 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
this.descriptionTemplateValueChanged(descriptionTemplateId);
|
||||
}
|
||||
});
|
||||
|
||||
this.formGroup.get('properties').valueChanges
|
||||
.pipe(takeUntil(this._destroyed))
|
||||
.subscribe(next => this.tocValidationService.validateForm());
|
||||
}
|
||||
|
||||
descriptionTemplateValueChanged(descriptionTemplateId: Guid) {
|
||||
if (descriptionTemplateId != null) {
|
||||
|
||||
this.descriptionTemplateService.getSingle(descriptionTemplateId, DescriptionEditorResolver.descriptionTemplateLookupFields()).pipe(takeUntil(this._destroyed))
|
||||
.subscribe(descriptionTemplate => {
|
||||
.subscribe(descriptionTemplate => {
|
||||
|
||||
this.initialTemplateId = descriptionTemplateId.toString();
|
||||
this.editorModel.properties = new DescriptionPropertyDefinitionEditorModel(this.editorModel.validationErrorModel).fromModel(null, descriptionTemplate, null);
|
||||
this.formGroup.setControl('properties', this.editorModel.buildProperties(this.visibilityRulesService));
|
||||
this.item.descriptionTemplate = descriptionTemplate;
|
||||
this.initialTemplateId = descriptionTemplateId.toString();
|
||||
this.editorModel.properties = new DescriptionPropertyDefinitionEditorModel(this.editorModel.validationErrorModel).fromModel(null, descriptionTemplate, null);
|
||||
this.formGroup.setControl('properties', this.editorModel.buildProperties(this.visibilityRulesService));
|
||||
this.item.descriptionTemplate = descriptionTemplate;
|
||||
|
||||
const sectionId = this.item.dmpDescriptionTemplate.sectionId;
|
||||
this.item.dmpDescriptionTemplate = this.item.dmp.dmpDescriptionTemplates.find(x => x.sectionId == sectionId && x.descriptionTemplateGroupId == descriptionTemplate.groupId);
|
||||
this.formGroup.get('dmpDescriptionTemplateId').setValue(this.item.dmpDescriptionTemplate.id);
|
||||
if (descriptionTemplate.definition) this.visibilityRulesService.setContext(this.item.descriptionTemplate.definition, this.formGroup.get('properties'));
|
||||
if (descriptionTemplate.definition) this.pageToFieldSetMap = this.mapPageToFieldSet(this.item.descriptionTemplate);
|
||||
const sectionId = this.item.dmpDescriptionTemplate.sectionId;
|
||||
this.item.dmpDescriptionTemplate = this.item.dmp.dmpDescriptionTemplates.find(x => x.sectionId == sectionId && x.descriptionTemplateGroupId == descriptionTemplate.groupId);
|
||||
this.formGroup.get('dmpDescriptionTemplateId').setValue(this.item.dmpDescriptionTemplate.id);
|
||||
if (descriptionTemplate.definition) this.visibilityRulesService.setContext(this.item.descriptionTemplate.definition, this.formGroup.get('properties'));
|
||||
if (descriptionTemplate.definition) this.pageToFieldSetMap = this.mapPageToFieldSet(this.item.descriptionTemplate);
|
||||
|
||||
this.registerFormListeners();
|
||||
},
|
||||
error => {
|
||||
this.formGroup.get('descriptionTemplateId').setValue(this.initialTemplateId && this.initialTemplateId != '' ? this.initialTemplateId : null);
|
||||
this.httpErrorHandlingService.handleBackedRequestError(error);
|
||||
});
|
||||
this.registerFormListeners();
|
||||
},
|
||||
error => {
|
||||
this.formGroup.get('descriptionTemplateId').setValue(this.initialTemplateId && this.initialTemplateId != '' ? this.initialTemplateId : null);
|
||||
this.httpErrorHandlingService.handleBackedRequestError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -756,8 +719,8 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
this.formService.removeAllBackEndErrors(this.formGroup);
|
||||
this.formService.touchAllFormFields(this.formGroup);
|
||||
this.formService.validateAllFormFields(this.formGroup);
|
||||
|
||||
this.tocValidationService.validateForm();
|
||||
|
||||
this.showTocEntriesErrors = true;
|
||||
if (!this.isFormValid()) {
|
||||
this.dialog.open(FormValidationErrorsDialogComponent, {
|
||||
data: {
|
||||
|
|
|
@ -28,7 +28,6 @@ export class DescriptionFormComponent extends BaseComponent implements OnInit, O
|
|||
@Input() validationErrorModel: ValidationErrorModel;
|
||||
|
||||
@Output() formChanged: EventEmitter<any> = new EventEmitter();
|
||||
@Output() fieldsetFocusChange: EventEmitter<string> = new EventEmitter<string>();
|
||||
|
||||
constructor(
|
||||
public descriptionFormAnnotationService: DescriptionFormAnnotationService,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Guid } from "@common/types/guid";
|
||||
import { AbstractControl } from "@angular/forms";
|
||||
import { ToCEntryType } from "./toc-entry-type.enum";
|
||||
|
||||
export interface ToCEntry {
|
||||
|
@ -10,5 +10,12 @@ export interface ToCEntry {
|
|||
// form: AbstractControl;
|
||||
numbering: string;
|
||||
ordinal: number;
|
||||
hidden?: boolean
|
||||
hidden?: boolean;
|
||||
visibilityRuleKey: string;
|
||||
validityAbstractControl: AbstractControl;
|
||||
|
||||
isLastEntry?: boolean;
|
||||
isFirstEntry?: boolean;
|
||||
previousEntry?: ToCEntry;
|
||||
NextEntry?: ToCEntry;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import { EventEmitter, Injectable } from "@angular/core";
|
||||
import { Observable } from "rxjs";
|
||||
|
||||
@Injectable()
|
||||
export class TableOfContentsService {
|
||||
|
||||
private _nextClickedEventEmmiter: EventEmitter<any> = new EventEmitter<any>();
|
||||
private _previousClickedEventEmmiter: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
getNextClickedEventObservable(): Observable<any> {
|
||||
return this._nextClickedEventEmmiter.asObservable();
|
||||
}
|
||||
|
||||
getPreviousEventObservable(): Observable<any> {
|
||||
return this._previousClickedEventEmmiter.asObservable();
|
||||
}
|
||||
|
||||
nextClicked(): void {
|
||||
this._nextClickedEventEmmiter.emit();
|
||||
}
|
||||
|
||||
previousClicked(): void {
|
||||
this._previousClickedEventEmmiter.emit();
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
import { EventEmitter, Injectable } from "@angular/core";
|
||||
|
||||
@Injectable()
|
||||
export class TableOfContentsValidationService {
|
||||
private _validateFormEvent: EventEmitter<any> = new EventEmitter<any>();
|
||||
get validateFormEvent(): EventEmitter<any> {
|
||||
return this._validateFormEvent;
|
||||
}
|
||||
|
||||
validateForm(): void {
|
||||
this._validateFormEvent.emit();
|
||||
}
|
||||
}
|
|
@ -1,56 +1,31 @@
|
|||
<div *ngFor="let entry of tocentries; index as idx">
|
||||
<!-- check if is visible -->
|
||||
<!-- <ng-container *ngIf="!hiddenEntries.includes(entry.id)"> -->
|
||||
<ng-container *ngIf="!hiddenEntries.includes(entry.id)">
|
||||
|
||||
<!-- Is fieldset and has no visible inputs -->
|
||||
<!-- <ng-container *ngIf="!(entry.type === tocEntryTypeEnum.FieldSet && !visibilityRulesService.scanIfChildsOfCompositeFieldHasVisibleItems(entry.form))"> TODO: add this bellow -->
|
||||
<!-- <ng-container *ngIf="!(entry.type === tocEntryTypeEnum.FieldSet)"> -->
|
||||
<ng-container *ngIf="visibilityRulesService.isVisibleMap[entry.visibilityRuleKey] ?? true">
|
||||
<ng-container >
|
||||
|
||||
<span class="table-entry"
|
||||
(click)="toggleExpand(idx);navigateToFieldSet(entry, $event); onEntrySelected(entry);"
|
||||
(click)="toggleExpand(idx); onEntrySelected(entry);"
|
||||
[ngStyle]="calculateStyle(entry)"
|
||||
[ngClass]="calculateClass(entry)"
|
||||
>
|
||||
<span [class.text-danger]="showErrors && propertiesFormGroup.get('entry.id')?.invalid && ( entry.type === tocEntryTypeEnum.FieldSet || (entry.type !== tocEntryTypeEnum.FieldSet && !expandChildren[idx])) && invalidChildsVisible(entry) ">
|
||||
<span [class.text-danger]="!isTocEntryValid(entry) && showErrors">
|
||||
{{entry.numbering}}. {{entry.label}}
|
||||
</span>
|
||||
<!-- <mat-icon style="transform: translateY(3px);" class="text-danger"
|
||||
*ngIf="showErrors && entry.form.invalid && entry.type !== tocEntryTypeEnum.FieldSet && !expandChildren[idx]">
|
||||
priority_high
|
||||
</mat-icon> -->
|
||||
<!-- <ng-container *ngIf="entry.subEntries && entry.subEntries.length && !expandChildren[idx]">
|
||||
<small>
|
||||
({{entry.subEntries.length}})
|
||||
</small>
|
||||
|
||||
</ng-container> -->
|
||||
</span>
|
||||
|
||||
</span>
|
||||
<!-- <div class="table-entry-container">
|
||||
</div> -->
|
||||
<div class="internal-table">
|
||||
<table-of-contents-internal
|
||||
[tocentries]="entry.subEntries"
|
||||
*ngIf="entry.subEntries && entry.subEntries.length && expandChildren[idx]"
|
||||
(entrySelected)="onEntrySelected($event)"
|
||||
[selected]="selected"
|
||||
[showErrors]="showErrors"
|
||||
[hiddenEntries]="hiddenEntries"
|
||||
[visibilityRulesService]="visibilityRulesService"
|
||||
[propertiesFormGroup]="propertiesFormGroup"
|
||||
[parentId]="entry.id"
|
||||
[parentMap]="updatedMap"
|
||||
(scrollFinished)="onScrollFinished($event)"
|
||||
(scrollStarted)="onScrollStarted($event)"
|
||||
[showErrors]="showErrors"
|
||||
>
|
||||
|
||||
</table-of-contents-internal>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
|
||||
|
||||
</ng-container>
|
||||
|
||||
</div>
|
|
@ -1,50 +1,35 @@
|
|||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, QueryList, SimpleChanges, ViewChildren } from '@angular/core';
|
||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core';
|
||||
import { UntypedFormGroup } from '@angular/forms';
|
||||
import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service';
|
||||
import { Guid } from '@common/types/guid';
|
||||
import { BaseComponent } from '@common/base/base.component';
|
||||
import { ToCEntry } from '../models/toc-entry';
|
||||
import { ToCEntryType } from '../models/toc-entry-type.enum';
|
||||
import { DescriptionFieldIndicator } from '../../description-editor.model';
|
||||
import { Observable, Subscription, map } from 'rxjs';
|
||||
import { TableOfContentsValidationService } from '../services/table-of-contents-validation-service';
|
||||
import { TableOfContentsComponent } from '../table-of-contents.component';
|
||||
|
||||
@Component({
|
||||
selector: 'table-of-contents-internal',
|
||||
styleUrls: ['./table-of-contents-internal.scss'],
|
||||
templateUrl: './table-of-contents-internal.html'
|
||||
})
|
||||
export class TableOfContentsInternal implements OnInit, OnDestroy {
|
||||
export class TableOfContentsInternal extends BaseComponent implements OnInit, OnDestroy {
|
||||
|
||||
@Input() tocentries: ToCEntry[] = null;
|
||||
@Input() selected: ToCEntry = null;
|
||||
// @Input() visibilityRules:Rule[] = [];
|
||||
@Output() entrySelected = new EventEmitter<ToCEntry>();
|
||||
@Output() scrollStarted = new EventEmitter<ToCEntry>();
|
||||
@Output() scrollFinished = new EventEmitter<ToCEntry>();
|
||||
@Input() propertiesFormGroup: UntypedFormGroup;
|
||||
|
||||
expandChildren: boolean[];
|
||||
tocEntryTypeEnum = ToCEntryType;
|
||||
@Input() showErrors: boolean = false;
|
||||
@Input() hiddenEntries: string[] = [];
|
||||
@Input() visibilityRulesService: VisibilityRulesService;
|
||||
@ViewChildren(TableOfContentsInternal) internalTables: QueryList<TableOfContentsInternal>;
|
||||
|
||||
@Input() parentId: string;
|
||||
@Input() parentMap: Map<string, DescriptionFieldIndicator[]> = new Map<string, DescriptionFieldIndicator[]>();
|
||||
@Input() updatedMap: Map<string, DescriptionFieldIndicator[]> = new Map<string, DescriptionFieldIndicator[]>();
|
||||
tocEntriesStateSubscriptions: Subscription[] = [];
|
||||
tocEntriesStateMap: Map<string, boolean> = new Map<string, boolean>();
|
||||
constructor() { super(); }
|
||||
|
||||
constructor(private tocValidationService: TableOfContentsValidationService) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
// console.log('component created' + JSON.stringify(this.tocentries));
|
||||
if (this.tocentries) {
|
||||
this.expandChildren = this.tocentries.map(() => false);
|
||||
if (this.selected) {
|
||||
for (let i = 0; i < this.tocentries.length; i++) {
|
||||
if (this._findTocEntryById(this.selected.id, this.tocentries[i].subEntries)) {
|
||||
if (TableOfContentsComponent._findTocEntryById(this.selected.id, this.tocentries[i].subEntries)) {
|
||||
if (this.expandChildren) {
|
||||
this.expandChildren[i] = true;
|
||||
}
|
||||
|
@ -52,17 +37,13 @@ export class TableOfContentsInternal implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.parentMap) {
|
||||
this.refreshErrorIndicators();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes.selected && this.selected) {
|
||||
for (let i = 0; i < this.tocentries.length; i++) {
|
||||
if (this._findTocEntryById(this.selected.id, this.tocentries[i].subEntries)) {
|
||||
if (TableOfContentsComponent._findTocEntryById(this.selected.id, this.tocentries[i].subEntries)) {
|
||||
if (this.expandChildren) {
|
||||
this.expandChildren[i] = true;
|
||||
}
|
||||
|
@ -70,127 +51,24 @@ export class TableOfContentsInternal implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changes.parentMap && this.parentMap) {
|
||||
this.refreshErrorIndicators();
|
||||
}
|
||||
// if (!this.isActive && this.links && this.links.length > 0) {
|
||||
// this.links.forEach(link => {
|
||||
// link.selected = false;
|
||||
// })
|
||||
// this.links[0].selected = true;
|
||||
// }
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.tocEntriesStateSubscriptions.forEach((errorSubscription: Subscription) => {
|
||||
errorSubscription.unsubscribe();
|
||||
});
|
||||
}
|
||||
|
||||
refreshErrorIndicators(): void {
|
||||
this.updatedMap = this.updateMap(this.tocentries, this.parentMap);
|
||||
for (let entry of this.tocentries) {
|
||||
this.tocEntriesStateMap.set(entry.id, this.hasErrors(entry.id));
|
||||
|
||||
this.tocEntriesStateSubscriptions.push(
|
||||
this.tocValidationService.validateFormEvent
|
||||
.pipe(map(() => this.hasErrors(entry.id)))
|
||||
.subscribe(next => {
|
||||
this.tocEntriesStateMap.set(entry.id, next);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
updateMap(entries: ToCEntry[], parentMap:Map<string, DescriptionFieldIndicator[]>): Map<string, DescriptionFieldIndicator[]> {
|
||||
if (this.parentId == null) return parentMap;
|
||||
|
||||
let updatedMap = new Map<string, DescriptionFieldIndicator[]>();
|
||||
|
||||
parentMap.forEach((fields: DescriptionFieldIndicator[], parentId: string) => {
|
||||
if (this.parentId === parentId) {
|
||||
for (let entry of entries) {
|
||||
let entryFields = fields.filter((field: DescriptionFieldIndicator) => field.sectionIds.includes(entry.id) || field.fieldSetId === entry.id || field.fieldId === entry.id )
|
||||
|
||||
updatedMap.set(entry.id, entryFields);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return updatedMap;
|
||||
}
|
||||
|
||||
hasErrors(entryId: string): boolean {
|
||||
if (this.updatedMap.size == 0) return false;
|
||||
|
||||
const fields: DescriptionFieldIndicator[] = this.updatedMap.get(entryId);
|
||||
|
||||
for (let field of fields) {
|
||||
let formFieldName: string = `fieldSets.${field.fieldSetId}.items.0.fields.${field.fieldId}.${field.type}`;
|
||||
if (this.isFormFieldValid(formFieldName) === false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
isFormFieldValid(formFieldName: string):boolean {
|
||||
const formField = this.propertiesFormGroup?.get(formFieldName);
|
||||
if (formField == null) return true;
|
||||
|
||||
if (formField.dirty === false
|
||||
&& formField.touched === false) return true;
|
||||
|
||||
return formField.valid;
|
||||
super.ngOnDestroy();
|
||||
}
|
||||
|
||||
toggleExpand(index) {
|
||||
this.expandChildren[index] = !this.expandChildren[index];
|
||||
// console.log(this.expandChildren);
|
||||
}
|
||||
|
||||
navigateToFieldSet(entry: ToCEntry, event) {
|
||||
if (entry.type === ToCEntryType.FieldSet) {
|
||||
this.onScrollStarted(entry);
|
||||
|
||||
const fieldSetId = entry.id;
|
||||
const element = document.getElementById(fieldSetId);
|
||||
if (element) {
|
||||
element.click();//open mat expansion panel
|
||||
|
||||
//scroll asyn in 200 ms so the expansion panel is expanded and the element coordinates are updated
|
||||
setTimeout(() => {
|
||||
const element = document.getElementById(fieldSetId);
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: 'smooth' });
|
||||
// element.focus({preventScroll: true});
|
||||
setTimeout(() => {
|
||||
this.scrollFinished.emit(entry);
|
||||
}, 1000);
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onEntrySelected(entry: ToCEntry) {
|
||||
this.entrySelected.emit(entry);
|
||||
}
|
||||
|
||||
onScrollStarted(entry: ToCEntry) {
|
||||
this.scrollStarted.emit(entry);
|
||||
}
|
||||
|
||||
onScrollFinished(entry: ToCEntry) {
|
||||
this.scrollFinished.emit(entry);
|
||||
}
|
||||
|
||||
|
||||
calculateStyle(entry: ToCEntry) {
|
||||
const style = {};
|
||||
style['font-size'] = entry.type === this.tocEntryTypeEnum.FieldSet ? '.9em' : '1em';
|
||||
style['font-size'] = entry.type === ToCEntryType.FieldSet ? '.9em' : '1em';
|
||||
return style;
|
||||
}
|
||||
|
||||
|
@ -201,64 +79,24 @@ export class TableOfContentsInternal implements OnInit, OnDestroy {
|
|||
myClass['selected'] = true;
|
||||
}
|
||||
|
||||
if (entry.type != this.tocEntryTypeEnum.FieldSet) {
|
||||
if (entry.type != ToCEntryType.FieldSet) {
|
||||
myClass['section'] = true;
|
||||
}
|
||||
|
||||
if(this.tocEntriesStateMap?.get(entry.id) === true) {
|
||||
myClass['text-danger'] = true;
|
||||
}
|
||||
return myClass;
|
||||
}
|
||||
|
||||
private _findTocEntryById(id: string, tocentries: ToCEntry[]): ToCEntry {
|
||||
if (!tocentries || !tocentries.length) {
|
||||
return null;
|
||||
isTocEntryValid(entry: ToCEntry): boolean {
|
||||
if (entry == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let tocEntryFound = tocentries.find(entry => entry.id === id);
|
||||
let currentValidity = entry.validityAbstractControl?.valid ?? true;
|
||||
if (!currentValidity) return currentValidity;
|
||||
entry.subEntries?.forEach(subEntry => {
|
||||
currentValidity = currentValidity && this.isTocEntryValid(subEntry);
|
||||
if (!currentValidity) return currentValidity;
|
||||
});
|
||||
|
||||
if (tocEntryFound) {
|
||||
return tocEntryFound;
|
||||
}
|
||||
|
||||
for (let entry of tocentries) {
|
||||
const result = this._findTocEntryById(id, entry.subEntries);
|
||||
if (result) {
|
||||
tocEntryFound = result;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return tocEntryFound ? tocEntryFound : null;
|
||||
}
|
||||
public invalidChildsVisible(entry: ToCEntry): boolean {
|
||||
if (!entry || !this.visibilityRulesService) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entry.type != this.tocEntryTypeEnum.FieldSet) {
|
||||
return entry.subEntries.some(_ => this.invalidChildsVisible(_));
|
||||
}
|
||||
if (entry.type === this.tocEntryTypeEnum.FieldSet) {
|
||||
const id = entry.id;
|
||||
if (!(this.visibilityRulesService.isVisibleMap[id.toString()])) {
|
||||
return false;
|
||||
}
|
||||
// const fieldsArray = entry.form.get('fields') as UntypedFormArray;
|
||||
const hasError = !entry.subEntries.every(field => {//every invalid field should be invisible
|
||||
//TODO: check this
|
||||
// if (field.invalid) {
|
||||
// const id = field.id;
|
||||
// const isVisible = this.visibilityRulesService.isVisibleMap[id);
|
||||
// if (isVisible) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
return true;
|
||||
});
|
||||
return hasError;
|
||||
}
|
||||
return false;
|
||||
return currentValidity;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,3 @@
|
|||
<div *ngIf="links?.length" class="row docs-toc-container">
|
||||
<div class="col-12 scroll-container">
|
||||
<span *ngFor="let link of links; let i = index" (click)="toggle(link); goToStep(link)" class="docs-level-{{link.type}} docs-link mt-0" [class.docs-active]="link.active">
|
||||
<span *ngIf="link.show" class="link-name"><span [class.selected]="link.selected && isActive">{{link.name}}</span></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="tocentries" class="row docs-toc-container">
|
||||
|
||||
<div class="scroll-container col-12 internal-table">
|
||||
|
@ -13,12 +5,8 @@
|
|||
[showErrors]="showErrors"
|
||||
(entrySelected)="onToCentrySelected($event)"
|
||||
[selected]="tocentrySelected"
|
||||
[hiddenEntries]="hiddenEntries"
|
||||
[visibilityRulesService]="visibilityRulesService"
|
||||
[propertiesFormGroup]="formGroup"
|
||||
[parentMap]="pageToFieldSetMap"
|
||||
(scrollFinished)="onScrollFinished($event)"
|
||||
(scrollStarted)="onScrollStarted($event)"
|
||||
>
|
||||
|
||||
</table-of-contents-internal>
|
||||
|
|
|
@ -1,32 +1,12 @@
|
|||
import { DOCUMENT } from '@angular/common';
|
||||
import { Component, EventEmitter, Inject, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core';
|
||||
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
|
||||
import { UntypedFormGroup } from '@angular/forms';
|
||||
import { DescriptionTemplate, DescriptionTemplateField, DescriptionTemplateFieldSet, DescriptionTemplateSection } from '@app/core/model/description-template/description-template';
|
||||
import { DescriptionTemplate, DescriptionTemplateFieldSet, DescriptionTemplateSection } from '@app/core/model/description-template/description-template';
|
||||
import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service';
|
||||
import { BaseComponent } from '@common/base/base.component';
|
||||
import { Subject, Subscription, interval } from 'rxjs';
|
||||
import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators';
|
||||
import { Observable, debounceTime, distinctUntilChanged, filter, mergeMap, take, takeUntil } from 'rxjs';
|
||||
import { ToCEntry } from './models/toc-entry';
|
||||
import { ToCEntryType } from './models/toc-entry-type.enum';
|
||||
import { TableOfContentsInternal } from './table-of-contents-internal/table-of-contents-internal';
|
||||
import { DescriptionFieldIndicator } from '../description-editor.model';
|
||||
|
||||
export interface Link {
|
||||
/* id of the section*/
|
||||
id: string;
|
||||
/* header type h3/h4 */
|
||||
type: string;
|
||||
/* If the anchor is in view of the page */
|
||||
active: boolean;
|
||||
/* name of the anchor */
|
||||
name: string;
|
||||
/* top offset px of the anchor */
|
||||
top: number;
|
||||
page: number;
|
||||
section: number;
|
||||
show: boolean;
|
||||
selected: boolean;
|
||||
}
|
||||
import { TableOfContentsService } from './services/table-of-contents-service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-table-of-contents',
|
||||
|
@ -35,30 +15,18 @@ export interface Link {
|
|||
})
|
||||
export class TableOfContentsComponent extends BaseComponent implements OnInit, OnChanges {
|
||||
|
||||
@ViewChild('internalTable') internalTable: TableOfContentsInternal;
|
||||
|
||||
|
||||
@Input() links: Link[];
|
||||
container: string;
|
||||
headerSelectors = '.toc-page-header, .toc-section-header, .toc-compositeField-header';
|
||||
@Output() stepFound = new EventEmitter<LinkToScroll>();
|
||||
@Output() currentLinks = new EventEmitter<Link[]>();
|
||||
@Output() entrySelected = new EventEmitter<any>();
|
||||
subscription: Subscription;
|
||||
linksSubject: Subject<HTMLElement[]> = new Subject<HTMLElement[]>();
|
||||
|
||||
@Input() isActive: boolean;
|
||||
@Input() showErrors: boolean = false;
|
||||
@Input() formGroup: UntypedFormGroup;
|
||||
@Input() descriptionTemplate: DescriptionTemplate;
|
||||
@Input() hasFocus: boolean = false;
|
||||
@Input() visibilityRulesService: VisibilityRulesService;
|
||||
|
||||
tocentries: ToCEntry[] = null;
|
||||
@Input() showErrors: boolean = false;
|
||||
@Input() selectedFieldsetId: string;
|
||||
|
||||
private _intersectionObserver: IntersectionObserver;
|
||||
|
||||
private _tocentrySelected: ToCEntry = null;
|
||||
private isSelecting: boolean = false;
|
||||
private isScrolling: boolean = false;
|
||||
private _intersectionObserver: IntersectionObserver;
|
||||
private _actOnObservation: boolean = true;
|
||||
public hiddenEntries: string[] = [];
|
||||
get tocentrySelected() {
|
||||
return this.hasFocus ? this._tocentrySelected : null;
|
||||
}
|
||||
|
@ -66,17 +34,9 @@ export class TableOfContentsComponent extends BaseComponent implements OnInit, O
|
|||
this._tocentrySelected = value;
|
||||
}
|
||||
|
||||
@Input() formGroup: UntypedFormGroup;
|
||||
@Input() descriptionTemplate: DescriptionTemplate;
|
||||
@Input() hasFocus: boolean = false;
|
||||
@Input() visibilityRulesService: VisibilityRulesService;
|
||||
show: boolean = false;
|
||||
|
||||
@Input() pageToFieldSetMap: Map<string, DescriptionFieldIndicator[]>;
|
||||
|
||||
constructor(
|
||||
@Inject(DOCUMENT) private _document: Document,
|
||||
// public visibilityRulesService: VisibilityRulesService
|
||||
private tableOfContentsService: TableOfContentsService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
@ -84,223 +44,78 @@ export class TableOfContentsComponent extends BaseComponent implements OnInit, O
|
|||
|
||||
ngOnInit(): void {
|
||||
|
||||
this.visibilityRulesService.getRulesChangedObservable().pipe(takeUntil(this._destroyed)).subscribe(data => {
|
||||
this.hiddenEntries = this._findHiddenEntries(this.tocentries);
|
||||
});
|
||||
if (this.descriptionTemplate) {
|
||||
this.tocentries = this.getTocEntries(this.descriptionTemplate);
|
||||
this.hiddenEntries = this._findHiddenEntries(this.tocentries);
|
||||
|
||||
} else {
|
||||
|
||||
//emit value every 500ms
|
||||
const source = interval(500);
|
||||
this.subscription = source.subscribe(val => {
|
||||
const headers = Array.from(this._document.querySelectorAll(this.headerSelectors)) as HTMLElement[];
|
||||
this.linksSubject.next(headers);
|
||||
});
|
||||
|
||||
// if (!this.links || this.links.length === 0) {
|
||||
// this.linksSubject.asObservable()
|
||||
// .pipe(distinctUntilChanged((p: HTMLElement[], q: HTMLElement[]) => JSON.stringify(p) == JSON.stringify(q)))
|
||||
// .subscribe(headers => {
|
||||
// const links: Array<Link> = [];
|
||||
|
||||
// if (headers.length) {
|
||||
// let page;
|
||||
// let section;
|
||||
// let show
|
||||
// for (const header of headers) {
|
||||
// let name;
|
||||
// let id;
|
||||
// if (header.classList.contains('toc-page-header')) { // deprecated after removing stepper
|
||||
// name = header.innerText.trim().replace(/^link/, '');
|
||||
// id = header.id;
|
||||
// page = header.id.split('_')[1];
|
||||
// section = undefined;
|
||||
// show = true;
|
||||
// } else if (header.classList.contains('toc-section-header')) {
|
||||
// name = header.childNodes[0].childNodes[0].childNodes[0].childNodes[1].childNodes[0].nodeValue.trim().replace(/^link/, '');
|
||||
// id = header.id;
|
||||
// page = header.id.split('.')[1];
|
||||
// section = header.id;
|
||||
// if (header.id.split('.')[4]) { show = false; }
|
||||
// else { show = true; }
|
||||
// } else if (header.classList.contains('toc-compositeField-header')) {
|
||||
// name = (header.childNodes[0]).nodeValue.trim().replace(/^link/, '');
|
||||
// id = header.id;
|
||||
// // id = header.parentElement.parentElement.parentElement.id;
|
||||
// show = false;
|
||||
// }
|
||||
// const { top } = header.getBoundingClientRect();
|
||||
// links.push({
|
||||
// name,
|
||||
// id,
|
||||
// type: header.tagName.toLowerCase(),
|
||||
// top: top,
|
||||
// active: false,
|
||||
// page: page,
|
||||
// section: section,
|
||||
// show: show,
|
||||
// selected: false
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// this.links = links;
|
||||
// // Initialize selected for button next on dataset wizard component editor
|
||||
// this.links.length > 0 ? this.links[0].selected = true : null;
|
||||
// })
|
||||
// }
|
||||
}
|
||||
|
||||
this.tableOfContentsService.getNextClickedEventObservable().pipe(takeUntil(this._destroyed)).subscribe(x => {
|
||||
//TODO: implement function to find next element
|
||||
// call onToCentrySelected()
|
||||
});
|
||||
|
||||
this.tableOfContentsService.getPreviousEventObservable().pipe(takeUntil(this._destroyed)).subscribe(x => {
|
||||
//TODO: implement function to find previous element
|
||||
// call onToCentrySelected()
|
||||
});
|
||||
}
|
||||
|
||||
private _findHiddenEntries(tocentries: ToCEntry[]): string[] {
|
||||
if (!tocentries) return [];
|
||||
|
||||
const invisibleEntries: string[] = []
|
||||
tocentries.forEach(entry => {
|
||||
if (entry.type === ToCEntryType.FieldSet) {
|
||||
const isVisible = this.visibilityRulesService.isVisibleMap[entry.id.toString()];
|
||||
if (!isVisible) {
|
||||
invisibleEntries.push(entry.id.toString());
|
||||
}
|
||||
} else {
|
||||
const hiddenEntries = this._findHiddenEntries(entry.subEntries);
|
||||
|
||||
if (entry.subEntries && (entry.subEntries.every(e => hiddenEntries.includes(e.id.toString())))) {
|
||||
//all children all hidden then hide parent node;
|
||||
invisibleEntries.push(entry.id.toString());
|
||||
} else {
|
||||
invisibleEntries.push(...hiddenEntries);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return invisibleEntries;
|
||||
}
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
|
||||
if (this.selectedFieldsetId) {
|
||||
this.onToCentrySelected(this._findTocEntryById(this.selectedFieldsetId, this.tocentries), false);
|
||||
this._actOnObservation = false;
|
||||
setTimeout(() => {
|
||||
this._actOnObservation = true;
|
||||
}, 1000);
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (changes['hasFocus'] && changes.hasFocus.currentValue) {
|
||||
this._resetObserver();
|
||||
|
||||
}
|
||||
if (changes['descriptionTemplate'] && changes.descriptionTemplate != null) {
|
||||
this.tocentries = this.getTocEntries(this.descriptionTemplate);
|
||||
this.hiddenEntries = this._findHiddenEntries(this.tocentries);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private _resetObserver() {
|
||||
if (this._intersectionObserver) {//clean up
|
||||
this._intersectionObserver.disconnect();
|
||||
this._intersectionObserver = null;
|
||||
}
|
||||
|
||||
const options = {
|
||||
root: null,
|
||||
rootMargin: '20% 0px -30% 0px',
|
||||
threshold: 0
|
||||
}
|
||||
|
||||
this._intersectionObserver = new IntersectionObserver((entries, observer) => {
|
||||
if (!this._actOnObservation) {
|
||||
return;
|
||||
new Observable(observer => {
|
||||
const options = {
|
||||
root: null,
|
||||
rootMargin: '20% 0px -30% 0px',
|
||||
threshold: [0, 0.2, 0.5, 1]
|
||||
}
|
||||
this._intersectionObserver = new IntersectionObserver(entries => {
|
||||
observer.next(entries);
|
||||
}, options);
|
||||
|
||||
entries.forEach(ie => {
|
||||
if (ie.isIntersecting) {
|
||||
const fieldsetsEtries = this._getAllFieldSets(this.tocentries);
|
||||
|
||||
fieldsetsEtries.forEach(e => {
|
||||
if (e.type === ToCEntryType.FieldSet) {
|
||||
try {
|
||||
if(!this.isScrolling) {
|
||||
const target_id = ie.target.id;
|
||||
if (this.visibilityRulesService.isVisibleMap[target_id] ?? true) {
|
||||
this.onToCentrySelected(this._findTocEntryById(target_id, this.tocentries));
|
||||
}
|
||||
}
|
||||
const targetElement = document.getElementById(e.id);
|
||||
this._intersectionObserver.observe(targetElement);
|
||||
} catch {
|
||||
console.log('element not found');
|
||||
}
|
||||
|
||||
// setTimeout(() => {
|
||||
// try {
|
||||
// if(!this.isSelecting) {
|
||||
// const target_id = ie.target.id;
|
||||
// if (this.visibilityRulesService.isVisibleMap[target_id] ?? true) {
|
||||
// this.onToCentrySelected(this._findTocEntryById(target_id, this.tocentries));
|
||||
// }
|
||||
// }
|
||||
// } catch {
|
||||
// }
|
||||
// }, 1000)
|
||||
}
|
||||
})
|
||||
}, options);
|
||||
});
|
||||
|
||||
const fieldsetsEtries = this._getAllFieldSets(this.tocentries);
|
||||
|
||||
fieldsetsEtries.forEach(e => {
|
||||
if (e.type === ToCEntryType.FieldSet) {
|
||||
try {
|
||||
const targetElement = document.getElementById(e.id);
|
||||
this._intersectionObserver.observe(targetElement);
|
||||
} catch {
|
||||
console.log('element not found');
|
||||
return () => { this._intersectionObserver.disconnect(); };
|
||||
}).pipe(
|
||||
takeUntil(this._destroyed),
|
||||
mergeMap((entries: IntersectionObserverEntry[]) => entries),
|
||||
filter(entry => entry.isIntersecting),
|
||||
debounceTime(200),
|
||||
distinctUntilChanged(),
|
||||
).subscribe(x => {
|
||||
if (x.isIntersecting) {
|
||||
const target_id = x.target.id;
|
||||
console.log(target_id);
|
||||
if (this.visibilityRulesService.isVisibleMap[target_id] ?? true) {
|
||||
this.tocentrySelected = TableOfContentsComponent._findTocEntryById(target_id, this.tocentries);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
goToStep(link: Link) {
|
||||
this.stepFound.emit({
|
||||
page: link.page,
|
||||
section: link.section
|
||||
});
|
||||
this.currentLinks.emit(this.links);
|
||||
|
||||
setTimeout(() => {
|
||||
const target = document.getElementById(link.id);
|
||||
target.scrollIntoView(true);
|
||||
|
||||
var scrolledY = window.scrollY;
|
||||
if (scrolledY) {
|
||||
window.scroll(0, scrolledY - 70);
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
toggle(headerLink: Link) {
|
||||
const headerPage = +headerLink.name.split(" ", 1);
|
||||
let innerPage;
|
||||
for (const link of this.links) {
|
||||
link.selected = false;
|
||||
if (link.type === 'mat-expansion-panel') {
|
||||
innerPage = +link.name.split(".", 1)[0];
|
||||
if (isNaN(innerPage)) { innerPage = +link.name.split(" ", 1) }
|
||||
} else if (link.type === 'h5') {
|
||||
innerPage = +link.name.split(".", 1)[0];
|
||||
}
|
||||
if (headerPage === innerPage && (link.type !== 'mat-expansion-panel' || (link.type === 'mat-expansion-panel' && link.id.split(".")[4]))) {
|
||||
link.show = !link.show;
|
||||
}
|
||||
}
|
||||
headerLink.selected = true;
|
||||
}
|
||||
|
||||
// getIndex(link: Link): number {
|
||||
// return +link.id.split("_", 2)[1];
|
||||
// }
|
||||
|
||||
|
||||
private _buildRecursivelySection(item: DescriptionTemplateSection): ToCEntry {
|
||||
if (!item) return null;
|
||||
|
||||
|
@ -328,18 +143,14 @@ export class TableOfContentsComponent extends BaseComponent implements OnInit, O
|
|||
subEntries: tempResult,
|
||||
subEntriesType: sections && sections.length ? ToCEntryType.Section : ToCEntryType.FieldSet,
|
||||
type: ToCEntryType.Section,
|
||||
ordinal: item.ordinal
|
||||
ordinal: item.ordinal,
|
||||
visibilityRuleKey: item.id,
|
||||
validityAbstractControl: this.formGroup.get('fieldSets').get(item.id)
|
||||
}
|
||||
}
|
||||
|
||||
private _buildRecursivelyFieldSet(item: DescriptionTemplateFieldSet): ToCEntry {
|
||||
if (!item) return null;
|
||||
const tempResult: ToCEntry[] = [];
|
||||
if (item && item.fields.length > 0) {
|
||||
item.fields.forEach(field => {
|
||||
tempResult.push(this._buildRecursivelyField(field));
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
// form: form,
|
||||
|
@ -349,22 +160,9 @@ export class TableOfContentsComponent extends BaseComponent implements OnInit, O
|
|||
subEntries: null,
|
||||
subEntriesType: ToCEntryType.Field,
|
||||
type: ToCEntryType.FieldSet,
|
||||
ordinal: item.ordinal
|
||||
};
|
||||
}
|
||||
|
||||
private _buildRecursivelyField(item: DescriptionTemplateField): ToCEntry {
|
||||
if (!item) return null;
|
||||
return {
|
||||
// form: form,
|
||||
id: item.id,
|
||||
label: null,
|
||||
numbering: 's',
|
||||
subEntries: null,
|
||||
subEntriesType: null,
|
||||
type: ToCEntryType.Field,
|
||||
ordinal: item.ordinal,
|
||||
hidden: false
|
||||
visibilityRuleKey: item.id,
|
||||
validityAbstractControl: this.formGroup.get('fieldSets').get(item.id)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -404,15 +202,15 @@ export class TableOfContentsComponent extends BaseComponent implements OnInit, O
|
|||
//build parent pages
|
||||
descriptionTemplate.definition.pages.forEach((pageElement, i) => {
|
||||
const tocEntry: ToCEntry = {
|
||||
// id: i + 'id',
|
||||
id: pageElement.id,
|
||||
label: pageElement.title,
|
||||
type: ToCEntryType.Page,
|
||||
// form: pageElement,
|
||||
numbering: (i + 1).toString(),
|
||||
subEntriesType: ToCEntryType.Section,
|
||||
subEntries: [],
|
||||
ordinal: pageElement.ordinal
|
||||
ordinal: pageElement.ordinal,
|
||||
visibilityRuleKey: pageElement.id,
|
||||
validityAbstractControl: null
|
||||
};
|
||||
|
||||
const sections = descriptionTemplate.definition.pages.find(x => x.id == pageElement.id)?.sections;
|
||||
|
@ -432,45 +230,10 @@ export class TableOfContentsComponent extends BaseComponent implements OnInit, O
|
|||
}
|
||||
|
||||
onToCentrySelected(entry: ToCEntry = null, execute: boolean = true) {
|
||||
if (!this.isSelecting) {
|
||||
this.isSelecting = true;
|
||||
this.tocentrySelected = entry;
|
||||
this.entrySelected.emit({ entry: entry, execute: execute });
|
||||
setTimeout(() => {
|
||||
this.isSelecting = false;
|
||||
}, 600);
|
||||
}
|
||||
this.tocentrySelected = entry;
|
||||
this.entrySelected.emit({ entry: entry, execute: execute });
|
||||
}
|
||||
|
||||
onScrollStarted(entry: ToCEntry) {
|
||||
this.isScrolling = true;
|
||||
}
|
||||
|
||||
onScrollFinished(entry: ToCEntry) {
|
||||
this.isScrolling = false;
|
||||
}
|
||||
|
||||
private _findTocEntryById(id: string, tocentries: ToCEntry[]): ToCEntry {
|
||||
if (!tocentries || !tocentries.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let tocEntryFound = tocentries.find(entry => entry.id === id);
|
||||
|
||||
if (tocEntryFound) {
|
||||
return tocEntryFound;
|
||||
}
|
||||
|
||||
for (let entry of tocentries) {
|
||||
const result = this._findTocEntryById(id, entry.subEntries);
|
||||
if (result) {
|
||||
tocEntryFound = result;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return tocEntryFound ? tocEntryFound : null;
|
||||
}
|
||||
/**
|
||||
* Get all filedsets in a tocentry array;
|
||||
* @param entries Tocentries to search in
|
||||
|
@ -492,15 +255,27 @@ export class TableOfContentsComponent extends BaseComponent implements OnInit, O
|
|||
return fieldsets;
|
||||
}
|
||||
|
||||
|
||||
public hasVisibleInvalidFields(): boolean {
|
||||
if (!this.internalTable || !this.tocentries) {
|
||||
return false;
|
||||
public static _findTocEntryById(id: string, tocentries: ToCEntry[]): ToCEntry {
|
||||
if (!tocentries || !tocentries.length) {
|
||||
return null;
|
||||
}
|
||||
return this.tocentries.some(e => this.internalTable.invalidChildsVisible(e));
|
||||
}
|
||||
|
||||
protected readonly console = console;
|
||||
let tocEntryFound = tocentries.find(entry => entry.id === id);
|
||||
|
||||
if (tocEntryFound) {
|
||||
return tocEntryFound;
|
||||
}
|
||||
|
||||
for (let entry of tocentries) {
|
||||
const result = this._findTocEntryById(id, entry.subEntries);
|
||||
if (result) {
|
||||
tocEntryFound = result;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return tocEntryFound ? tocEntryFound : null;
|
||||
}
|
||||
}
|
||||
|
||||
export interface LinkToScroll {
|
||||
|
|
|
@ -5,12 +5,12 @@ import { TableOfContentsInternal } from './table-of-contents-internal/table-of-c
|
|||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service';
|
||||
import { TableOfContentsComponent } from './table-of-contents.component';
|
||||
import { TableOfContentsValidationService } from './services/table-of-contents-validation-service';
|
||||
import { TableOfContentsService } from './services/table-of-contents-service';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, RouterModule, MatIconModule],
|
||||
declarations: [TableOfContentsComponent, TableOfContentsInternal],
|
||||
exports: [TableOfContentsComponent],
|
||||
providers: [VisibilityRulesService, TableOfContentsValidationService]
|
||||
providers: [VisibilityRulesService, TableOfContentsService]
|
||||
})
|
||||
export class TableOfContentsModule { }
|
||||
|
|
Loading…
Reference in New Issue