diff --git a/dmp-frontend/src/app/ui/annotations/annotation-dialog-component/annotation-dialog.component.html b/dmp-frontend/src/app/ui/annotations/annotation-dialog-component/annotation-dialog.component.html index 606023bf3..bda190867 100644 --- a/dmp-frontend/src/app/ui/annotations/annotation-dialog-component/annotation-dialog.component.html +++ b/dmp-frontend/src/app/ui/annotations/annotation-dialog-component/annotation-dialog.component.html @@ -8,6 +8,11 @@
+
+ +
diff --git a/dmp-frontend/src/app/ui/annotations/annotation-dialog-component/annotation-dialog.component.ts b/dmp-frontend/src/app/ui/annotations/annotation-dialog-component/annotation-dialog.component.ts index a42a2ada0..5626e9b58 100644 --- a/dmp-frontend/src/app/ui/annotations/annotation-dialog-component/annotation-dialog.component.ts +++ b/dmp-frontend/src/app/ui/annotations/annotation-dialog-component/annotation-dialog.component.ts @@ -217,4 +217,23 @@ export class AnnotationDialogComponent extends BaseComponent { enableReply(threadId: string): void { this.replyEnabledPerThread[threadId] = true; } + + copyLink() { + const el = document.createElement('textarea'); + let domain = `${window.location.protocol}//${window.location.hostname}`; + if (window.location.port && window.location.port != '') domain += `:${window.location.port}` + const descriptionSectionPath = this.routerUtils.generateUrl(['descriptions/edit', this.entityId, 'f', this.anchor, 'annotation'].join('/')); + el.value = domain + descriptionSectionPath; + el.setAttribute('readonly', ''); + el.style.position = 'absolute'; + el.style.left = '-9999px'; + document.body.appendChild(el); + el.select(); + document.execCommand('copy'); + document.body.removeChild(el); + this.uiNotificationService.snackBarNotification( + this.language.instant('DESCRIPTION-EDITOR.QUESTION.EXTENDED-DESCRIPTION.COPY-LINK-SUCCESSFUL'), + SnackBarNotificationLevel.Success + ); + } } diff --git a/dmp-frontend/src/app/ui/description/editor/description-editor.component.html b/dmp-frontend/src/app/ui/description/editor/description-editor.component.html index 2bf48ec73..6aa96e43a 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-editor.component.html +++ b/dmp-frontend/src/app/ui/description/editor/description-editor.component.html @@ -107,7 +107,22 @@
- + +
diff --git a/dmp-frontend/src/app/ui/description/editor/description-editor.component.ts b/dmp-frontend/src/app/ui/description/editor/description-editor.component.ts index f501902b1..752f7cb80 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-editor.component.ts +++ b/dmp-frontend/src/app/ui/description/editor/description-editor.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core'; +import { AfterViewInit, ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core'; import { AbstractControl, UntypedFormArray, UntypedFormGroup } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { Title } from '@angular/platform-browser'; @@ -44,6 +44,7 @@ import { TableOfContentsService } from './table-of-contents/services/table-of-co import { TableOfContentsComponent } from './table-of-contents/table-of-contents.component'; import { RouterUtilsService } from '@app/core/services/router/router-utils.service'; import { DescriptionFormService } from './description-form/components/services/description-form.service'; +import { DescriptionFormAnnotationService } from './description-form/description-form-annotation.service'; @Component({ selector: 'app-description-editor-component', @@ -51,7 +52,7 @@ import { DescriptionFormService } from './description-form/components/services/d styleUrls: ['./description-editor.component.scss'], providers: [DescriptionEditorService] }) -export class DescriptionEditorComponent extends BaseEditor implements OnInit { +export class DescriptionEditorComponent extends BaseEditor implements OnInit, AfterViewInit { isNew = true; isDeleted = false; @@ -71,6 +72,10 @@ export class DescriptionEditorComponent extends BaseEditor = new Map(); @@ -105,6 +110,7 @@ export class DescriptionEditorComponent extends BaseEditor void) { this.descriptionService.getSingle(itemId, DescriptionEditorEntityResolver.lookupFields()) .pipe(map(data => data as Description), takeUntil(this._destroyed)) diff --git a/dmp-frontend/src/app/ui/description/editor/description-editor.routing.ts b/dmp-frontend/src/app/ui/description/editor/description-editor.routing.ts index e4d9acc30..6a0e30f00 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-editor.routing.ts +++ b/dmp-frontend/src/app/ui/description/editor/description-editor.routing.ts @@ -41,6 +41,47 @@ const routes: Routes = [ title: 'DESCRIPTION-EDITOR.TITLE-EDIT-DESCRIPTION', } }, + { + path: ':id/f/:fieldsetId', + canActivate: [AuthGuard], + component: DescriptionEditorComponent, + canDeactivate: [PendingChangesGuard], + resolve: { + 'entity': DescriptionEditorEntityResolver, + 'permissions': DescriptionEditorPermissionsResolver, + }, + data: { + breadcrumbs: true, + getFromTitleService: true, + usePrefix: false, + ...BreadcrumbService.generateRouteDataConfiguration({ + skipNavigation: true, + }), + title: 'DESCRIPTION-EDITOR.TITLE-EDIT-DESCRIPTION', + scrollToField: true, + } + }, + { + path: ':id/f/:fieldsetId/annotation', + canActivate: [AuthGuard], + component: DescriptionEditorComponent, + canDeactivate: [PendingChangesGuard], + resolve: { + 'entity': DescriptionEditorEntityResolver, + 'permissions': DescriptionEditorPermissionsResolver, + }, + data: { + breadcrumbs: true, + getFromTitleService: true, + usePrefix: false, + ...BreadcrumbService.generateRouteDataConfiguration({ + skipNavigation: true, + }), + title: 'DESCRIPTION-EDITOR.TITLE-EDIT-DESCRIPTION', + scrollToField: true, + openAnnotation: true, + } + }, { path: ':dmpId/:dmpSectionId', canActivate: [AuthGuard], diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.html b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.html index c16a7b36c..35771b003 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.html +++ b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.html @@ -6,8 +6,13 @@
- +
+
+
diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.ts b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.ts index 68f7c9deb..a6447b848 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.ts +++ b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.ts @@ -17,6 +17,9 @@ import { DescriptionFormAnnotationService } from '../../description-form-annotat import { DescriptionPropertyDefinitionFieldSet } from '@app/core/model/description/description'; import { DescriptionFormService } from '../services/description-form.service'; import { DescriptionTemplateFieldType } from '@app/core/common/enum/description-template-field-type'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { RouterUtilsService } from '@app/core/services/router/router-utils.service'; +import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'app-description-form-field-set', @@ -53,10 +56,13 @@ export class DescriptionFormFieldSetComponent extends BaseComponent { descriptionTemplateFieldType = DescriptionTemplateFieldType; constructor( + private routerUtils: RouterUtilsService, private dialog: MatDialog, private changeDetector: ChangeDetectorRef, private descriptionFormAnnotationService: DescriptionFormAnnotationService, private descriptionFormService: DescriptionFormService, + private uiNotificationService: UiNotificationService, + private language: TranslateService, ) { super(); } @@ -71,6 +77,10 @@ export class DescriptionFormFieldSetComponent extends BaseComponent { this.changeDetector.markForCheck(); } }); + + this.descriptionFormAnnotationService.getOpenAnnotationSubjectObservable().pipe(takeUntil(this._destroyed)).subscribe( (anchorFieldsetId: string) => { + if (anchorFieldsetId && anchorFieldsetId == this.fieldSet.id) this.showAnnotations(anchorFieldsetId); + }); } canAddMultiplicityField(): boolean{ @@ -135,6 +145,25 @@ export class DescriptionFormFieldSetComponent extends BaseComponent { }); } + copyLink(fieldsetId: string) { + const el = document.createElement('textarea'); + let domain = `${window.location.protocol}//${window.location.hostname}`; + if (window.location.port && window.location.port != '') domain += `:${window.location.port}` + const descriptionSectionPath = this.routerUtils.generateUrl(['descriptions/edit', this.descriptionId.toString(), 'f', fieldsetId].join('/')); + el.value = domain + descriptionSectionPath; + el.setAttribute('readonly', ''); + el.style.position = 'absolute'; + el.style.left = '-9999px'; + document.body.appendChild(el); + el.select(); + document.execCommand('copy'); + document.body.removeChild(el); + this.uiNotificationService.snackBarNotification( + this.language.instant('DESCRIPTION-EDITOR.QUESTION.EXTENDED-DESCRIPTION.COPY-LINK-SUCCESSFUL'), + SnackBarNotificationLevel.Success + ); + } + // // // Annotations diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/description-form-annotation.service.ts b/dmp-frontend/src/app/ui/description/editor/description-form/description-form-annotation.service.ts index 0cdc17ff8..1fcfa1d86 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-form/description-form-annotation.service.ts +++ b/dmp-frontend/src/app/ui/description/editor/description-form/description-form-annotation.service.ts @@ -7,7 +7,7 @@ import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/serv import { BaseService } from '@common/base/base.service'; import { Guid } from '@common/types/guid'; import { TranslateService } from '@ngx-translate/core'; -import { BehaviorSubject, Observable } from 'rxjs'; +import { BehaviorSubject, Observable, Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { nameof } from 'ts-simple-nameof'; @@ -20,6 +20,7 @@ export class DescriptionFormAnnotationService extends BaseService { private entityId: Guid; private annotationsPerAnchor: Map; private annotationCountSubject: BehaviorSubject> = new BehaviorSubject>(null); + private openAnnotationSubject: Subject = new Subject(); constructor( private annotationService: AnnotationService, @@ -37,6 +38,14 @@ export class DescriptionFormAnnotationService extends BaseService { public getAnnotationCountObservable(): Observable> { return this.annotationCountSubject.asObservable(); } + + public getOpenAnnotationSubjectObservable(): Observable { + return this.openAnnotationSubject.asObservable(); + } + + public οpenAnnotationDialog(next: any): void { + this.openAnnotationSubject.next(next); + } public refreshAnnotations() { const lookup: AnnotationLookup = new AnnotationLookup(); diff --git a/dmp-frontend/src/app/ui/description/editor/resolvers/description-editor-entity.resolver.ts b/dmp-frontend/src/app/ui/description/editor/resolvers/description-editor-entity.resolver.ts index d5dffa114..95096a3be 100644 --- a/dmp-frontend/src/app/ui/description/editor/resolvers/description-editor-entity.resolver.ts +++ b/dmp-frontend/src/app/ui/description/editor/resolvers/description-editor-entity.resolver.ts @@ -161,8 +161,13 @@ export class DescriptionEditorEntityResolver extends BaseEditorResolver { const dmpId = route.paramMap.get('dmpId'); const dmpSectionId = route.paramMap.get('dmpSectionId'); const copyDmpId = route.paramMap.get('copyDmpId'); - // const cloneid = route.paramMap.get('cloneid'); + const fieldsetId = route.paramMap.get('fieldsetId'); if (id != null && copyDmpId == null && dmpSectionId == null) { + if (fieldsetId != null) { + this.breadcrumbService.addExcludedParam(fieldsetId, true); + this.breadcrumbService.addExcludedParam('f', true); + this.breadcrumbService.addExcludedParam('annotation', true); + } return this.descriptionService.getSingle(Guid.parse(id), fields).pipe(tap(d => this.breadcrumbService.addIdResolvedValue(d.id.toString(), d.label))); } else if (dmpId != null && dmpSectionId != null && copyDmpId == null) { return this.dmpService.getSingle(Guid.parse(dmpId), DescriptionEditorEntityResolver.dmpLookupFields()) diff --git a/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.ts b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.ts index 5294c4d57..f4baaed6e 100644 --- a/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.ts +++ b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.ts @@ -21,6 +21,7 @@ export class TableOfContentsComponent extends BaseComponent implements OnInit, O @Input() descriptionTemplate: DescriptionTemplate; @Input() hasFocus: boolean = false; @Input() visibilityRulesService: VisibilityRulesService; + @Input() anchorFieldsetId: string; tocentries: ToCEntry[] = null; @@ -29,7 +30,6 @@ export class TableOfContentsComponent extends BaseComponent implements OnInit, O private _tocentrySelected: ToCEntry = null; get tocentrySelected() { return this._tocentrySelected; - // return this.hasFocus ? this._tocentrySelected : null; } set tocentrySelected(value) { this._tocentrySelected = value; @@ -47,6 +47,10 @@ export class TableOfContentsComponent extends BaseComponent implements OnInit, O if (this.descriptionTemplate) { this.tocentries = this.getTocEntries(this.descriptionTemplate); + if (this.anchorFieldsetId) { + const anchorTocentry = TableOfContentsComponent._findTocEntryById(this.anchorFieldsetId, this.tocentries); + if (anchorTocentry) setTimeout(() => { this.onToCentrySelected(anchorTocentry) }, 300); + } } this.tableOfContentsService.getNextClickedEventObservable().pipe(takeUntil(this._destroyed)).subscribe(x => { @@ -105,6 +109,10 @@ export class TableOfContentsComponent extends BaseComponent implements OnInit, O if (changes['descriptionTemplate'] && changes.descriptionTemplate != null) { this.tocentries = this.getTocEntries(this.descriptionTemplate); } + if (changes['anchorFieldsetId'] && changes.anchorFieldsetId != null) { + const anchorTocentry = TableOfContentsComponent._findTocEntryById(this.anchorFieldsetId, this.tocentries); + if (anchorTocentry) setTimeout(() => { this.onToCentrySelected(anchorTocentry) }, 300); + } } private _resetObserver() { diff --git a/dmp-frontend/src/assets/i18n/baq.json b/dmp-frontend/src/assets/i18n/baq.json index 080333214..5ff82ebc3 100644 --- a/dmp-frontend/src/assets/i18n/baq.json +++ b/dmp-frontend/src/assets/i18n/baq.json @@ -982,6 +982,13 @@ "CANCEL": "Cancel", "UPDATE": "Update" } + }, + "QUESTION": { + "EXTENDED-DESCRIPTION": { + "COPY-LINK": "Copy Link", + "COPY-LINK-SUCCESSFUL": "Link copied", + "ANNOTATIONS": "Comment" + } } }, "DESCRIPTION-COPY-DIALOG": { diff --git a/dmp-frontend/src/assets/i18n/de.json b/dmp-frontend/src/assets/i18n/de.json index 8d6845bd0..4019935b3 100644 --- a/dmp-frontend/src/assets/i18n/de.json +++ b/dmp-frontend/src/assets/i18n/de.json @@ -982,6 +982,13 @@ "CANCEL": "Cancel", "UPDATE": "Update" } + }, + "QUESTION": { + "EXTENDED-DESCRIPTION": { + "COPY-LINK": "Copy Link", + "COPY-LINK-SUCCESSFUL": "Link copied", + "ANNOTATIONS": "Comment" + } } }, "DESCRIPTION-COPY-DIALOG": { diff --git a/dmp-frontend/src/assets/i18n/en.json b/dmp-frontend/src/assets/i18n/en.json index 91e5bad11..d6e5978c1 100644 --- a/dmp-frontend/src/assets/i18n/en.json +++ b/dmp-frontend/src/assets/i18n/en.json @@ -982,6 +982,13 @@ "CANCEL": "Cancel", "UPDATE": "Update" } + }, + "QUESTION": { + "EXTENDED-DESCRIPTION": { + "COPY-LINK": "Copy Link", + "COPY-LINK-SUCCESSFUL": "Link copied", + "ANNOTATIONS": "Comment" + } } }, "DESCRIPTION-COPY-DIALOG": { diff --git a/dmp-frontend/src/assets/i18n/es.json b/dmp-frontend/src/assets/i18n/es.json index 2f40ca448..656d2c37f 100644 --- a/dmp-frontend/src/assets/i18n/es.json +++ b/dmp-frontend/src/assets/i18n/es.json @@ -982,6 +982,13 @@ "CANCEL": "Cancel", "UPDATE": "Update" } + }, + "QUESTION": { + "EXTENDED-DESCRIPTION": { + "COPY-LINK": "Copy Link", + "COPY-LINK-SUCCESSFUL": "Link copied", + "ANNOTATIONS": "Comment" + } } }, "DESCRIPTION-COPY-DIALOG": { diff --git a/dmp-frontend/src/assets/i18n/gr.json b/dmp-frontend/src/assets/i18n/gr.json index 924e5c8ec..20ccef6df 100644 --- a/dmp-frontend/src/assets/i18n/gr.json +++ b/dmp-frontend/src/assets/i18n/gr.json @@ -982,6 +982,13 @@ "CANCEL": "Cancel", "UPDATE": "Update" } + }, + "QUESTION": { + "EXTENDED-DESCRIPTION": { + "COPY-LINK": "Copy Link", + "COPY-LINK-SUCCESSFUL": "Link copied", + "ANNOTATIONS": "Comment" + } } }, "DESCRIPTION-COPY-DIALOG": { diff --git a/dmp-frontend/src/assets/i18n/hr.json b/dmp-frontend/src/assets/i18n/hr.json index 6aff0b298..5bbeebd43 100644 --- a/dmp-frontend/src/assets/i18n/hr.json +++ b/dmp-frontend/src/assets/i18n/hr.json @@ -982,6 +982,13 @@ "CANCEL": "Cancel", "UPDATE": "Update" } + }, + "QUESTION": { + "EXTENDED-DESCRIPTION": { + "COPY-LINK": "Copy Link", + "COPY-LINK-SUCCESSFUL": "Link copied", + "ANNOTATIONS": "Comment" + } } }, "DESCRIPTION-COPY-DIALOG": { diff --git a/dmp-frontend/src/assets/i18n/pl.json b/dmp-frontend/src/assets/i18n/pl.json index 2ca62e48f..28ef34c03 100644 --- a/dmp-frontend/src/assets/i18n/pl.json +++ b/dmp-frontend/src/assets/i18n/pl.json @@ -982,6 +982,13 @@ "CANCEL": "Cancel", "UPDATE": "Update" } + }, + "QUESTION": { + "EXTENDED-DESCRIPTION": { + "COPY-LINK": "Copy Link", + "COPY-LINK-SUCCESSFUL": "Link copied", + "ANNOTATIONS": "Comment" + } } }, "DESCRIPTION-COPY-DIALOG": { diff --git a/dmp-frontend/src/assets/i18n/pt.json b/dmp-frontend/src/assets/i18n/pt.json index 689e52eef..863f742a5 100644 --- a/dmp-frontend/src/assets/i18n/pt.json +++ b/dmp-frontend/src/assets/i18n/pt.json @@ -982,6 +982,13 @@ "CANCEL": "Cancel", "UPDATE": "Update" } + }, + "QUESTION": { + "EXTENDED-DESCRIPTION": { + "COPY-LINK": "Copy Link", + "COPY-LINK-SUCCESSFUL": "Link copied", + "ANNOTATIONS": "Comment" + } } }, "DESCRIPTION-COPY-DIALOG": { diff --git a/dmp-frontend/src/assets/i18n/sk.json b/dmp-frontend/src/assets/i18n/sk.json index c90f33246..a01575da6 100644 --- a/dmp-frontend/src/assets/i18n/sk.json +++ b/dmp-frontend/src/assets/i18n/sk.json @@ -982,6 +982,13 @@ "CANCEL": "Cancel", "UPDATE": "Update" } + }, + "QUESTION": { + "EXTENDED-DESCRIPTION": { + "COPY-LINK": "Copy Link", + "COPY-LINK-SUCCESSFUL": "Link copied", + "ANNOTATIONS": "Comment" + } } }, "DESCRIPTION-COPY-DIALOG": { diff --git a/dmp-frontend/src/assets/i18n/sr.json b/dmp-frontend/src/assets/i18n/sr.json index 61402de56..968601ffc 100644 --- a/dmp-frontend/src/assets/i18n/sr.json +++ b/dmp-frontend/src/assets/i18n/sr.json @@ -982,6 +982,13 @@ "CANCEL": "Cancel", "UPDATE": "Update" } + }, + "QUESTION": { + "EXTENDED-DESCRIPTION": { + "COPY-LINK": "Copy Link", + "COPY-LINK-SUCCESSFUL": "Link copied", + "ANNOTATIONS": "Comment" + } } }, "DESCRIPTION-COPY-DIALOG": { diff --git a/dmp-frontend/src/assets/i18n/tr.json b/dmp-frontend/src/assets/i18n/tr.json index b1dbd10ed..8237ef6c7 100644 --- a/dmp-frontend/src/assets/i18n/tr.json +++ b/dmp-frontend/src/assets/i18n/tr.json @@ -982,6 +982,13 @@ "CANCEL": "Cancel", "UPDATE": "Update" } + }, + "QUESTION": { + "EXTENDED-DESCRIPTION": { + "COPY-LINK": "Copy Link", + "COPY-LINK-SUCCESSFUL": "Link copied", + "ANNOTATIONS": "Comment" + } } }, "DESCRIPTION-COPY-DIALOG": {