Merge remote-tracking branch 'upstream/dspace-8_x' into w2p-117544_support-for-disabled-elements-for-screen-readers-8.0

This commit is contained in:
Jens Vannerum
2024-08-27 11:23:37 +02:00
72 changed files with 324 additions and 156 deletions

View File

@@ -165,6 +165,7 @@
"@angular-eslint/no-output-native": "warn", "@angular-eslint/no-output-native": "warn",
"@angular-eslint/no-output-on-prefix": "warn", "@angular-eslint/no-output-on-prefix": "warn",
"@angular-eslint/no-conflicting-lifecycle": "warn", "@angular-eslint/no-conflicting-lifecycle": "warn",
"@angular-eslint/use-lifecycle-interface": "error",
"@typescript-eslint/no-inferrable-types":[ "@typescript-eslint/no-inferrable-types":[
"error", "error",

View File

@@ -4,7 +4,7 @@
# Test build: # Test build:
# docker build -f Dockerfile.dist -t dspace/dspace-angular:latest-dist . # docker build -f Dockerfile.dist -t dspace/dspace-angular:latest-dist .
FROM node:18-alpine as build FROM node:18-alpine AS build
# Ensure Python and other build tools are available # Ensure Python and other build tools are available
# These are needed to install some node modules, especially on linux/arm64 # These are needed to install some node modules, especially on linux/arm64

View File

@@ -59,19 +59,19 @@ A default/demo version of this image is built *automatically*.
## To refresh / pull DSpace images from Dockerhub ## To refresh / pull DSpace images from Dockerhub
``` ```
docker-compose -f docker/docker-compose.yml pull docker compose -f docker/docker-compose.yml pull
``` ```
## To build DSpace images using code in your branch ## To build DSpace images using code in your branch
``` ```
docker-compose -f docker/docker-compose.yml build docker compose -f docker/docker-compose.yml build
``` ```
## To start DSpace (REST and Angular) from your branch ## To start DSpace (REST and Angular) from your branch
This command provides a quick way to start both the frontend & backend from this single codebase This command provides a quick way to start both the frontend & backend from this single codebase
``` ```
docker-compose -p d8 -f docker/docker-compose.yml -f docker/docker-compose-rest.yml up -d docker compose -p d8 -f docker/docker-compose.yml -f docker/docker-compose-rest.yml up -d
``` ```
Keep in mind, you may also start the backend by cloning the 'DSpace/DSpace' GitHub repository separately. See the next section. Keep in mind, you may also start the backend by cloning the 'DSpace/DSpace' GitHub repository separately. See the next section.
@@ -86,14 +86,14 @@ _The system will be started in 2 steps. Each step shares the same docker network
From 'DSpace/DSpace' clone (build first as needed): From 'DSpace/DSpace' clone (build first as needed):
``` ```
docker-compose -p d8 up -d docker compose -p d8 up -d
``` ```
NOTE: More detailed instructions on starting the backend via Docker can be found in the [Docker Compose instructions for the Backend](https://github.com/DSpace/DSpace/blob/main/dspace/src/main/docker-compose/README.md). NOTE: More detailed instructions on starting the backend via Docker can be found in the [Docker Compose instructions for the Backend](https://github.com/DSpace/DSpace/blob/main/dspace/src/main/docker-compose/README.md).
From 'DSpace/dspace-angular' clone (build first as needed) From 'DSpace/dspace-angular' clone (build first as needed)
``` ```
docker-compose -p d8 -f docker/docker-compose.yml up -d docker compose -p d8 -f docker/docker-compose.yml up -d
``` ```
At this point, you should be able to access the UI from http://localhost:4000, At this point, you should be able to access the UI from http://localhost:4000,
@@ -105,21 +105,21 @@ This allows you to run the Angular UI in *production* mode, pointing it at the d
(https://demo.dspace.org/server/ or https://sandbox.dspace.org/server/). (https://demo.dspace.org/server/ or https://sandbox.dspace.org/server/).
``` ```
docker-compose -f docker/docker-compose-dist.yml pull docker compose -f docker/docker-compose-dist.yml pull
docker-compose -f docker/docker-compose-dist.yml build docker compose -f docker/docker-compose-dist.yml build
docker-compose -p d8 -f docker/docker-compose-dist.yml up -d docker compose -p d8 -f docker/docker-compose-dist.yml up -d
``` ```
## Ingest test data from AIPDIR ## Ingest test data from AIPDIR
Create an administrator Create an administrator
``` ```
docker-compose -p d8 -f docker/cli.yml run --rm dspace-cli create-administrator -e test@test.edu -f admin -l user -p admin -c en docker compose -p d8 -f docker/cli.yml run --rm dspace-cli create-administrator -e test@test.edu -f admin -l user -p admin -c en
``` ```
Load content from AIP files Load content from AIP files
``` ```
docker-compose -p d8 -f docker/cli.yml -f ./docker/cli.ingest.yml run --rm dspace-cli docker compose -p d8 -f docker/cli.yml -f ./docker/cli.ingest.yml run --rm dspace-cli
``` ```
## Alternative Ingest - Use Entities dataset ## Alternative Ingest - Use Entities dataset
@@ -127,12 +127,12 @@ _Delete your docker volumes or use a unique project (-p) name_
Start DSpace with Database Content from a database dump Start DSpace with Database Content from a database dump
``` ```
docker-compose -p d8 -f docker/docker-compose.yml -f docker/docker-compose-rest.yml -f docker/db.entities.yml up -d docker compose -p d8 -f docker/docker-compose.yml -f docker/docker-compose-rest.yml -f docker/db.entities.yml up -d
``` ```
Load assetstore content and trigger a re-index of the repository Load assetstore content and trigger a re-index of the repository
``` ```
docker-compose -p d8 -f docker/cli.yml -f docker/cli.assetstore.yml run --rm dspace-cli docker compose -p d8 -f docker/cli.yml -f docker/cli.assetstore.yml run --rm dspace-cli
``` ```
## End to end testing of the REST API (runs in GitHub Actions CI). ## End to end testing of the REST API (runs in GitHub Actions CI).
@@ -140,5 +140,5 @@ _In this instance, only the REST api runs in Docker using the Entities dataset.
This command is only really useful for testing our Continuous Integration process. This command is only really useful for testing our Continuous Integration process.
``` ```
docker-compose -p d8ci -f docker/docker-compose-ci.yml up -d docker compose -p d8ci -f docker/docker-compose-ci.yml up -d
``` ```

View File

@@ -14,7 +14,7 @@
# # Therefore, it should be kept in sync with that file # # Therefore, it should be kept in sync with that file
services: services:
dspacedb: dspacedb:
image: dspace/dspace-postgres-pgcrypto::${DSPACE_VER:-latest}-loadsql image: "${DOCKER_OWNER:-dspace}/dspace-postgres-pgcrypto:${DSPACE_VER:-latest}-loadsql"
environment: environment:
# This LOADSQL should be kept in sync with the URL in DSpace/DSpace # This LOADSQL should be kept in sync with the URL in DSpace/DSpace
# This SQL is available from https://github.com/DSpace-Labs/AIP-Files/releases/tag/demo-entities-data # This SQL is available from https://github.com/DSpace-Labs/AIP-Files/releases/tag/demo-entities-data
@@ -34,4 +34,4 @@ services:
- | - |
while (!</dev/tcp/dspacedb/5432) > /dev/null 2>&1; do sleep 1; done; while (!</dev/tcp/dspacedb/5432) > /dev/null 2>&1; do sleep 1; done;
/dspace/bin/dspace database migrate ignored /dspace/bin/dspace database migrate ignored
java -jar /dspace/webapps/server-boot.jar --dspace.dir=/dspace java -jar /dspace/webapps/server-boot.jar --dspace.dir=/dspace

View File

@@ -101,7 +101,7 @@ services:
# * First, run precreate-core to create the core (if it doesn't yet exist). If exists already, this is a no-op # * First, run precreate-core to create the core (if it doesn't yet exist). If exists already, this is a no-op
# * Second, copy configsets to this core: # * Second, copy configsets to this core:
# Updates to Solr configs require the container to be rebuilt/restarted: # Updates to Solr configs require the container to be rebuilt/restarted:
# `docker-compose -p d7 -f docker/docker-compose.yml -f docker/docker-compose-rest.yml up -d --build dspacesolr` # `docker compose -p d7 -f docker/docker-compose.yml -f docker/docker-compose-rest.yml up -d --build dspacesolr`
entrypoint: entrypoint:
- /bin/bash - /bin/bash
- '-c' - '-c'

View File

@@ -1,6 +1,6 @@
{ {
"name": "dspace-angular", "name": "dspace-angular",
"version": "8.0.0", "version": "8.1.0-next",
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"config:watch": "nodemon", "config:watch": "nodemon",

View File

@@ -4,7 +4,10 @@ import {
NgForOf, NgForOf,
NgIf, NgIf,
} from '@angular/common'; } from '@angular/common';
import { Component } from '@angular/core'; import {
Component,
OnDestroy,
} from '@angular/core';
import { import {
Router, Router,
RouterLink, RouterLink,
@@ -60,7 +63,7 @@ import { MetadataSchemaFormComponent } from './metadata-schema-form/metadata-sch
* A component used for managing all existing metadata schemas within the repository. * A component used for managing all existing metadata schemas within the repository.
* The admin can create, edit or delete metadata schemas here. * The admin can create, edit or delete metadata schemas here.
*/ */
export class MetadataRegistryComponent { export class MetadataRegistryComponent implements OnDestroy {
/** /**
* A list of all the current metadata schemas within the repository * A list of all the current metadata schemas within the repository

View File

@@ -4,6 +4,7 @@ import {
} from '@angular/common'; } from '@angular/common';
import { import {
Component, Component,
OnInit,
ViewChild, ViewChild,
} from '@angular/core'; } from '@angular/core';
import { import {
@@ -40,7 +41,7 @@ import { FilteredCollections } from './filtered-collections.model';
], ],
standalone: true, standalone: true,
}) })
export class FilteredCollectionsComponent { export class FilteredCollectionsComponent implements OnInit {
queryForm: FormGroup; queryForm: FormGroup;
results: FilteredCollections = new FilteredCollections(); results: FilteredCollections = new FilteredCollections();

View File

@@ -5,6 +5,7 @@ import {
} from '@angular/common'; } from '@angular/common';
import { import {
Component, Component,
OnInit,
ViewChild, ViewChild,
} from '@angular/core'; } from '@angular/core';
import { import {
@@ -68,7 +69,7 @@ import { QueryPredicate } from './query-predicate.model';
], ],
standalone: true, standalone: true,
}) })
export class FilteredItemsComponent { export class FilteredItemsComponent implements OnInit {
collections: OptionVO[]; collections: OptionVO[];
presetQueries: PresetQuery[]; presetQueries: PresetQuery[];
@@ -92,7 +93,7 @@ export class FilteredItemsComponent {
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private restService: DspaceRestService) {} private restService: DspaceRestService) {}
ngOnInit() { ngOnInit(): void {
this.loadCollections(); this.loadCollections();
this.loadPresetQueries(); this.loadPresetQueries();
this.loadMetadataFields(); this.loadMetadataFields();

View File

@@ -1,4 +1,7 @@
import { Component } from '@angular/core'; import {
Component,
OnInit,
} from '@angular/core';
import { RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { getCollectionEditRoute } from '../../../../../collection-page/collection-page-routing-paths'; import { getCollectionEditRoute } from '../../../../../collection-page/collection-page-routing-paths';
@@ -21,10 +24,10 @@ import { SearchResultGridElementComponent } from '../../../../../shared/object-g
/** /**
* The component for displaying a list element for a collection search result on the admin search page * The component for displaying a list element for a collection search result on the admin search page
*/ */
export class CollectionAdminSearchResultGridElementComponent extends SearchResultGridElementComponent<CollectionSearchResult, Collection> { export class CollectionAdminSearchResultGridElementComponent extends SearchResultGridElementComponent<CollectionSearchResult, Collection> implements OnInit {
editPath: string; editPath: string;
ngOnInit() { ngOnInit(): void {
super.ngOnInit(); super.ngOnInit();
this.editPath = getCollectionEditRoute(this.dso.uuid); this.editPath = getCollectionEditRoute(this.dso.uuid);
} }

View File

@@ -1,4 +1,7 @@
import { Component } from '@angular/core'; import {
Component,
OnInit,
} from '@angular/core';
import { RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { getCommunityEditRoute } from '../../../../../community-page/community-page-routing-paths'; import { getCommunityEditRoute } from '../../../../../community-page/community-page-routing-paths';
@@ -21,10 +24,10 @@ import { SearchResultGridElementComponent } from '../../../../../shared/object-g
/** /**
* The component for displaying a list element for a community search result on the admin search page * The component for displaying a list element for a community search result on the admin search page
*/ */
export class CommunityAdminSearchResultGridElementComponent extends SearchResultGridElementComponent<CommunitySearchResult, Community> { export class CommunityAdminSearchResultGridElementComponent extends SearchResultGridElementComponent<CommunitySearchResult, Community> implements OnInit {
editPath: string; editPath: string;
ngOnInit() { ngOnInit(): void {
super.ngOnInit(); super.ngOnInit();
this.editPath = getCommunityEditRoute(this.dso.uuid); this.editPath = getCommunityEditRoute(this.dso.uuid);
} }

View File

@@ -1,4 +1,7 @@
import { Component } from '@angular/core'; import {
Component,
OnInit,
} from '@angular/core';
import { RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
@@ -22,10 +25,10 @@ import { SearchResultListElementComponent } from '../../../../../shared/object-l
/** /**
* The component for displaying a list element for a collection search result on the admin search page * The component for displaying a list element for a collection search result on the admin search page
*/ */
export class CollectionAdminSearchResultListElementComponent extends SearchResultListElementComponent<CollectionSearchResult, Collection> { export class CollectionAdminSearchResultListElementComponent extends SearchResultListElementComponent<CollectionSearchResult, Collection> implements OnInit {
editPath: string; editPath: string;
ngOnInit() { ngOnInit(): void {
super.ngOnInit(); super.ngOnInit();
this.editPath = getCollectionEditRoute(this.dso.uuid); this.editPath = getCollectionEditRoute(this.dso.uuid);
} }

View File

@@ -1,4 +1,7 @@
import { Component } from '@angular/core'; import {
Component,
OnInit,
} from '@angular/core';
import { RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
@@ -22,10 +25,10 @@ import { SearchResultListElementComponent } from '../../../../../shared/object-l
/** /**
* The component for displaying a list element for a community search result on the admin search page * The component for displaying a list element for a community search result on the admin search page
*/ */
export class CommunityAdminSearchResultListElementComponent extends SearchResultListElementComponent<CommunitySearchResult, Community> { export class CommunityAdminSearchResultListElementComponent extends SearchResultListElementComponent<CommunitySearchResult, Community> implements OnInit {
editPath: string; editPath: string;
ngOnInit() { ngOnInit(): void {
super.ngOnInit(); super.ngOnInit();
this.editPath = getCommunityEditRoute(this.dso.uuid); this.editPath = getCommunityEditRoute(this.dso.uuid);
} }

View File

@@ -1,5 +1,8 @@
import { AsyncPipe } from '@angular/common'; import { AsyncPipe } from '@angular/common';
import { Component } from '@angular/core'; import {
Component,
OnInit,
} from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
@@ -28,7 +31,7 @@ import { hasValue } from '../../../shared/empty.util';
], ],
standalone: true, standalone: true,
}) })
export class CollectionCurateComponent { export class CollectionCurateComponent implements OnInit {
dsoRD$: Observable<RemoteData<Collection>>; dsoRD$: Observable<RemoteData<Collection>>;
collectionName$: Observable<string>; collectionName$: Observable<string>;

View File

@@ -97,7 +97,7 @@ export class CollectionSourceControlsComponent implements OnInit, OnDestroy {
) { ) {
} }
ngOnInit() { ngOnInit(): void {
// ensure the contentSource gets updated after being set to stale // ensure the contentSource gets updated after being set to stale
this.contentSource$ = this.collectionService.findByHref(this.collection._links.self.href, false).pipe( this.contentSource$ = this.collectionService.findByHref(this.collection._links.self.href, false).pipe(
getAllSucceededRemoteDataPayload(), getAllSucceededRemoteDataPayload(),

View File

@@ -27,6 +27,14 @@ export class ForwardClientIpInterceptor implements HttpInterceptor {
*/ */
intercept(httpRequest: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { intercept(httpRequest: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const clientIp = this.req.get('x-forwarded-for') || this.req.connection.remoteAddress; const clientIp = this.req.get('x-forwarded-for') || this.req.connection.remoteAddress;
return next.handle(httpRequest.clone({ setHeaders: { 'X-Forwarded-For': clientIp } })); const headers = { 'X-Forwarded-For': clientIp };
// if the request has a user-agent retain it
const userAgent = this.req.get('user-agent');
if (userAgent) {
headers['User-Agent'] = userAgent;
}
return next.handle(httpRequest.clone({ setHeaders: headers }));
} }
} }

View File

@@ -31,7 +31,7 @@ export class ClientMathService extends MathService {
protected mathJaxOptions = { protected mathJaxOptions = {
tex: { tex: {
inlineMath: [['$', '$'], ['\\(', '\\)']], inlineMath: [['$', '$'], ['$$', '$$'], ['\\(', '\\)']],
}, },
svg: { svg: {
fontCache: 'global', fontCache: 'global',
@@ -108,7 +108,7 @@ export class ClientMathService extends MathService {
*/ */
render(element: HTMLElement) { render(element: HTMLElement) {
if (environment.markdown.mathjax) { if (environment.markdown.mathjax) {
this._window.nativeWindow.MathJax.typesetPromise([element]); return (window as any).MathJax.typesetPromise([element]) as Promise<any>;
} }
} }
} }

View File

@@ -22,8 +22,8 @@ export class MockMathService extends MathService {
return of(true); return of(true);
} }
render(element: HTMLElement): void { render(element: HTMLElement): Promise<any> {
return; return Promise.resolve();
} }
} }

View File

@@ -15,5 +15,5 @@ export abstract class MathService {
protected abstract registerMathJaxAsync(config: MathJaxConfig): Promise<any>; protected abstract registerMathJaxAsync(config: MathJaxConfig): Promise<any>;
abstract ready(): Observable<boolean>; abstract ready(): Observable<boolean>;
abstract render(element: HTMLElement): void; abstract render(element: HTMLElement): Promise<any>;
} }

View File

@@ -47,6 +47,6 @@ export class ServerMathService extends MathService {
} }
render(element: HTMLElement) { render(element: HTMLElement) {
return; return Promise.resolve();
} }
} }

View File

@@ -1,5 +1,8 @@
/* eslint-disable max-classes-per-file */ /* eslint-disable max-classes-per-file */
import { Injectable } from '@angular/core'; import {
Injectable,
OnDestroy,
} from '@angular/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { Duplicate } from '../../shared/object-list/duplicate-data/duplicate.model'; import { Duplicate } from '../../shared/object-list/duplicate-data/duplicate.model';
@@ -33,7 +36,8 @@ import { HALEndpointService } from '../shared/hal-endpoint.service';
* *
*/ */
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class SubmissionDuplicateDataService extends BaseDataService<Duplicate> implements SearchData<Duplicate> { export class SubmissionDuplicateDataService extends BaseDataService<Duplicate>
implements SearchData<Duplicate>, OnDestroy {
/** /**
* The ResponseParsingService constructor name * The ResponseParsingService constructor name

View File

@@ -1,21 +1,25 @@
<div class="item-metadata" *ngIf="form"> <div class="item-metadata" *ngIf="form">
<div class="button-row top d-flex my-2 space-children-mr ml-gap"> <div class="button-row top d-flex my-2 space-children-mr ml-gap">
<button class="mr-auto btn btn-success" id="dso-add-btn" [dsDisabled]="form.newValue || (saving$ | async)" <button class="mr-auto btn btn-success" id="dso-add-btn" [dsDisabled]="form.newValue || (saving$ | async)"
[attr.aria-label]="dsoType + '.edit.metadata.add-button' | translate"
[title]="dsoType + '.edit.metadata.add-button' | translate" [title]="dsoType + '.edit.metadata.add-button' | translate"
(click)="add()"><i class="fas fa-plus" aria-hidden="true"></i> (click)="add()"><i class="fas fa-plus" aria-hidden="true"></i>
<span class="d-none d-sm-inline">&nbsp;{{ dsoType + '.edit.metadata.add-button' | translate }}</span> <span class="d-none d-sm-inline">&nbsp;{{ dsoType + '.edit.metadata.add-button' | translate }}</span>
</button> </button>
<button class="btn btn-warning ml-1" id="dso-reinstate-btn" *ngIf="isReinstatable" [dsDisabled]="(saving$ | async)" <button class="btn btn-warning ml-1" id="dso-reinstate-btn" *ngIf="isReinstatable" [dsDisabled]="(saving$ | async)"
[attr.aria-label]="dsoType + '.edit.metadata.reinstate-button' | translate"
[title]="dsoType + '.edit.metadata.reinstate-button' | translate" [title]="dsoType + '.edit.metadata.reinstate-button' | translate"
(click)="reinstate()"><i class="fas fa-undo-alt" aria-hidden="true"></i> (click)="reinstate()"><i class="fas fa-undo-alt" aria-hidden="true"></i>
<span class="d-none d-sm-inline">&nbsp;{{ dsoType + '.edit.metadata.reinstate-button' | translate }}</span> <span class="d-none d-sm-inline">&nbsp;{{ dsoType + '.edit.metadata.reinstate-button' | translate }}</span>
</button> </button>
<button class="btn btn-primary ml-1" id="dso-save-btn" [dsDisabled]="!hasChanges || (saving$ | async)" <button class="btn btn-primary ml-1" id="dso-save-btn" [dsDisabled]="!hasChanges || (saving$ | async)"
[attr.aria-label]="dsoType + '.edit.metadata.save-button' | translate"
[title]="dsoType + '.edit.metadata.save-button' | translate" [title]="dsoType + '.edit.metadata.save-button' | translate"
(click)="submit()"><i class="fas fa-save" aria-hidden="true"></i> (click)="submit()"><i class="fas fa-save" aria-hidden="true"></i>
<span class="d-none d-sm-inline">&nbsp;{{ dsoType + '.edit.metadata.save-button' | translate }}</span> <span class="d-none d-sm-inline">&nbsp;{{ dsoType + '.edit.metadata.save-button' | translate }}</span>
</button> </button>
<button class="btn btn-danger ml-1" id="dso-discard-btn" *ngIf="!isReinstatable" <button class="btn btn-danger ml-1" id="dso-discard-btn" *ngIf="!isReinstatable"
[attr.aria-label]="dsoType + '.edit.metadata.discard-button' | translate"
[title]="dsoType + '.edit.metadata.discard-button' | translate" [title]="dsoType + '.edit.metadata.discard-button' | translate"
[dsDisabled]="!hasChanges || (saving$ | async)" [dsDisabled]="!hasChanges || (saving$ | async)"
(click)="discard()"><i class="fas fa-times" aria-hidden="true"></i> (click)="discard()"><i class="fas fa-times" aria-hidden="true"></i>
@@ -74,16 +78,19 @@
<div class="button-row bottom d-inline-block w-100"> <div class="button-row bottom d-inline-block w-100">
<div class="mt-2 float-right space-children-mr ml-gap"> <div class="mt-2 float-right space-children-mr ml-gap">
<button class="btn btn-warning" *ngIf="isReinstatable" [dsDisabled]="(saving$ | async)" <button class="btn btn-warning" *ngIf="isReinstatable" [dsDisabled]="(saving$ | async)"
[attr.aria-label]="dsoType + '.edit.metadata.reinstate-button' | translate"
[title]="dsoType + '.edit.metadata.reinstate-button' | translate" [title]="dsoType + '.edit.metadata.reinstate-button' | translate"
(click)="reinstate()"> (click)="reinstate()">
<i class="fas fa-undo-alt" aria-hidden="true"></i> {{ dsoType + '.edit.metadata.reinstate-button' | translate }} <i class="fas fa-undo-alt" aria-hidden="true"></i> {{ dsoType + '.edit.metadata.reinstate-button' | translate }}
</button> </button>
<button class="btn btn-primary" [dsDisabled]="!hasChanges || (saving$ | async)" <button class="btn btn-primary" [dsDisabled]="!hasChanges || (saving$ | async)"
[attr.aria-label]="dsoType + '.edit.metadata.save-button' | translate"
[title]="dsoType + '.edit.metadata.save-button' | translate" [title]="dsoType + '.edit.metadata.save-button' | translate"
(click)="submit()"> (click)="submit()">
<i class="fas fa-save" aria-hidden="true"></i> {{ dsoType + '.edit.metadata.save-button' | translate }} <i class="fas fa-save" aria-hidden="true"></i> {{ dsoType + '.edit.metadata.save-button' | translate }}
</button> </button>
<button class="btn btn-danger" *ngIf="!isReinstatable" <button class="btn btn-danger" *ngIf="!isReinstatable"
[attr.aria-label]="dsoType + '.edit.metadata.discard-button' | translate"
[title]="dsoType + '.edit.metadata.discard-button' | translate" [title]="dsoType + '.edit.metadata.discard-button' | translate"
[dsDisabled]="!hasChanges || (saving$ | async)" [dsDisabled]="!hasChanges || (saving$ | async)"
(click)="discard()"> (click)="discard()">

View File

@@ -7,6 +7,7 @@ import {
import { import {
Component, Component,
Inject, Inject,
OnInit,
} from '@angular/core'; } from '@angular/core';
import { RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
@@ -36,7 +37,7 @@ import { ThemedThumbnailComponent } from '../../../../../thumbnail/themed-thumbn
/** /**
* The component for displaying a list element for an item search result of the type Person * The component for displaying a list element for an item search result of the type Person
*/ */
export class PersonSearchResultListElementComponent extends ItemSearchResultListElementComponent { export class PersonSearchResultListElementComponent extends ItemSearchResultListElementComponent implements OnInit {
public constructor( public constructor(
protected truncatableService: TruncatableService, protected truncatableService: TruncatableService,

View File

@@ -2,7 +2,10 @@ import {
AsyncPipe, AsyncPipe,
NgIf, NgIf,
} from '@angular/common'; } from '@angular/common';
import { Component } from '@angular/core'; import {
Component,
OnInit,
} from '@angular/core';
import { import {
ActivatedRoute, ActivatedRoute,
Router, Router,
@@ -47,7 +50,7 @@ import { BrowserOnlyPipe } from '../../shared/utils/browser-only.pipe';
/** /**
* Component for a user to enter a new password for a forgot token. * Component for a user to enter a new password for a forgot token.
*/ */
export class ForgotPasswordFormComponent { export class ForgotPasswordFormComponent implements OnInit {
registration$: Observable<Registration>; registration$: Observable<Registration>;

View File

@@ -10,6 +10,7 @@ import {
Component, Component,
ElementRef, ElementRef,
Inject, Inject,
OnDestroy,
OnInit, OnInit,
PLATFORM_ID, PLATFORM_ID,
} from '@angular/core'; } from '@angular/core';
@@ -62,7 +63,7 @@ import { VarDirective } from '../../shared/utils/var.directive';
standalone: true, standalone: true,
imports: [VarDirective, NgIf, NgClass, NgFor, ListableObjectComponentLoaderComponent, ErrorComponent, ThemedLoadingComponent, AsyncPipe, TranslateModule], imports: [VarDirective, NgIf, NgClass, NgFor, ListableObjectComponentLoaderComponent, ErrorComponent, ThemedLoadingComponent, AsyncPipe, TranslateModule],
}) })
export class RecentItemListComponent implements OnInit { export class RecentItemListComponent implements OnInit, OnDestroy {
itemRD$: Observable<RemoteData<PaginatedList<Item>>>; itemRD$: Observable<RemoteData<PaginatedList<Item>>>;
paginationConfig: PaginationComponentOptions; paginationConfig: PaginationComponentOptions;
sortConfig: SortOptions; sortConfig: SortOptions;

View File

@@ -3,7 +3,10 @@ import {
NgForOf, NgForOf,
NgIf, NgIf,
} from '@angular/common'; } from '@angular/common';
import { Component } from '@angular/core'; import {
Component,
OnInit,
} from '@angular/core';
import { import {
ActivatedRoute, ActivatedRoute,
Router, Router,
@@ -47,7 +50,7 @@ import { AbstractSimpleItemActionComponent } from '../simple-item-action/abstrac
/** /**
* Component responsible for rendering the Item Register DOI page * Component responsible for rendering the Item Register DOI page
*/ */
export class ItemRegisterDoiComponent extends AbstractSimpleItemActionComponent { export class ItemRegisterDoiComponent extends AbstractSimpleItemActionComponent implements OnInit {
protected messageKey = 'register-doi'; protected messageKey = 'register-doi';
doiToUpdateMessage = 'item.edit.' + this.messageKey + '.to-update'; doiToUpdateMessage = 'item.edit.' + this.messageKey + '.to-update';

View File

@@ -7,6 +7,7 @@ import {
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
Component, Component,
OnDestroy,
OnInit, OnInit,
} from '@angular/core'; } from '@angular/core';
import { import {
@@ -79,7 +80,7 @@ import { ItemOperation } from '../item-operation/itemOperation.model';
/** /**
* Component for displaying an item's status * Component for displaying an item's status
*/ */
export class ItemStatusComponent implements OnInit { export class ItemStatusComponent implements OnInit, OnDestroy {
/** /**
* The item to display the status for * The item to display the status for

View File

@@ -2,7 +2,10 @@ import {
AsyncPipe, AsyncPipe,
NgIf, NgIf,
} from '@angular/common'; } from '@angular/common';
import { Component } from '@angular/core'; import {
Component,
OnInit,
} from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
@@ -28,7 +31,7 @@ import { ItemVersionsComponent } from '../../versions/item-versions.component';
/** /**
* Component for listing and managing an item's version history * Component for listing and managing an item's version history
*/ */
export class ItemVersionHistoryComponent { export class ItemVersionHistoryComponent implements OnInit {
/** /**
* The item to display the version history for * The item to display the version history for
*/ */

View File

@@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common';
import { import {
Component, Component,
Input, Input,
OnChanges,
OnDestroy, OnDestroy,
OnInit, OnInit,
SimpleChanges, SimpleChanges,
@@ -56,7 +57,7 @@ import { PaginationComponentOptions } from '../../../shared/pagination/paginatio
], ],
standalone: true, standalone: true,
}) })
export class OrcidQueueComponent implements OnInit, OnDestroy { export class OrcidQueueComponent implements OnInit, OnDestroy, OnChanges {
/** /**
* The item for which showing the orcid settings * The item for which showing the orcid settings

View File

@@ -10,6 +10,7 @@ import {
ElementRef, ElementRef,
Inject, Inject,
Input, Input,
OnInit,
PLATFORM_ID, PLATFORM_ID,
} from '@angular/core'; } from '@angular/core';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
@@ -43,7 +44,7 @@ import { AbstractIncrementalListComponent } from '../abstract-incremental-list/a
* This component is used for displaying relations between items * This component is used for displaying relations between items
* It expects a parent item and relationship type, as well as a label to display on top * It expects a parent item and relationship type, as well as a label to display on top
*/ */
export class RelatedItemsComponent extends AbstractIncrementalListComponent<Observable<RemoteData<PaginatedList<Item>>>> { export class RelatedItemsComponent extends AbstractIncrementalListComponent<Observable<RemoteData<PaginatedList<Item>>>> implements OnInit {
/** /**
* The parent of the list of related items to display * The parent of the list of related items to display

View File

@@ -6,6 +6,7 @@ import {
Component, Component,
EventEmitter, EventEmitter,
Input, Input,
OnDestroy,
OnInit, OnInit,
} from '@angular/core'; } from '@angular/core';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
@@ -111,7 +112,7 @@ export interface QualityAssuranceEventData {
* Component to display a modal window for linking a project to an Quality Assurance event * Component to display a modal window for linking a project to an Quality Assurance event
* Shows information about the selected project and a selectable list. * Shows information about the selected project and a selectable list.
*/ */
export class ProjectEntryImportModalComponent implements OnInit { export class ProjectEntryImportModalComponent implements OnInit, OnDestroy {
/** /**
* The external source entry * The external source entry
*/ */

View File

@@ -5,7 +5,9 @@ import {
NgIf, NgIf,
} from '@angular/common'; } from '@angular/common';
import { import {
AfterViewInit,
Component, Component,
OnDestroy,
OnInit, OnInit,
} from '@angular/core'; } from '@angular/core';
import { RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
@@ -40,7 +42,7 @@ import { NotificationsStateService } from '../../notifications-state.service';
standalone: true, standalone: true,
imports: [AlertComponent, NgIf, ThemedLoadingComponent, PaginationComponent, NgFor, RouterLink, AsyncPipe, TranslateModule, DatePipe], imports: [AlertComponent, NgIf, ThemedLoadingComponent, PaginationComponent, NgFor, RouterLink, AsyncPipe, TranslateModule, DatePipe],
}) })
export class QualityAssuranceSourceComponent implements OnInit { export class QualityAssuranceSourceComponent implements OnDestroy, OnInit, AfterViewInit {
/** /**
* The pagination system configuration for HTML listing. * The pagination system configuration for HTML listing.

View File

@@ -4,8 +4,10 @@ import {
NgIf, NgIf,
} from '@angular/common'; } from '@angular/common';
import { import {
AfterViewInit,
Component, Component,
Input, Input,
OnDestroy,
OnInit, OnInit,
} from '@angular/core'; } from '@angular/core';
import { import {
@@ -50,7 +52,7 @@ import { SuggestionTargetsStateService } from '../suggestion-targets.state.servi
], ],
standalone: true, standalone: true,
}) })
export class PublicationClaimComponent implements OnInit { export class PublicationClaimComponent implements AfterViewInit, OnDestroy, OnInit {
/** /**
* The source for which to list targets * The source for which to list targets

View File

@@ -2,6 +2,7 @@ import { NgIf } from '@angular/common';
import { import {
Component, Component,
Input, Input,
OnInit,
Optional, Optional,
} from '@angular/core'; } from '@angular/core';
import { import {
@@ -27,7 +28,7 @@ import { ValueInputComponent } from '../value-input.component';
standalone: true, standalone: true,
imports: [FormsModule, NgIf, TranslateModule], imports: [FormsModule, NgIf, TranslateModule],
}) })
export class DateValueInputComponent extends ValueInputComponent<string> { export class DateValueInputComponent extends ValueInputComponent<string> implements OnInit {
/** /**
* The current value of the date string * The current value of the date string
*/ */
@@ -38,7 +39,7 @@ export class DateValueInputComponent extends ValueInputComponent<string> {
*/ */
@Input() initialValue; @Input() initialValue;
ngOnInit() { ngOnInit(): void {
this.value = this.initialValue; this.value = this.initialValue;
} }

View File

@@ -2,6 +2,7 @@ import { NgIf } from '@angular/common';
import { import {
Component, Component,
Input, Input,
OnInit,
Optional, Optional,
} from '@angular/core'; } from '@angular/core';
import { import {
@@ -27,7 +28,7 @@ import { ValueInputComponent } from '../value-input.component';
standalone: true, standalone: true,
imports: [FormsModule, NgIf, TranslateModule], imports: [FormsModule, NgIf, TranslateModule],
}) })
export class StringValueInputComponent extends ValueInputComponent<string> { export class StringValueInputComponent extends ValueInputComponent<string> implements OnInit {
/** /**
* The current value of the string * The current value of the string
*/ */
@@ -38,7 +39,7 @@ export class StringValueInputComponent extends ValueInputComponent<string> {
*/ */
@Input() initialValue; @Input() initialValue;
ngOnInit() { ngOnInit(): void {
this.value = this.initialValue; this.value = this.initialValue;
} }

View File

@@ -7,6 +7,7 @@ import {
EventEmitter, EventEmitter,
Input, Input,
OnChanges, OnChanges,
OnInit,
Optional, Optional,
Output, Output,
SimpleChanges, SimpleChanges,
@@ -39,7 +40,7 @@ import { ParameterSelectComponent } from './parameter-select/parameter-select.co
standalone: true, standalone: true,
imports: [NgIf, NgFor, ParameterSelectComponent, TranslateModule], imports: [NgIf, NgFor, ParameterSelectComponent, TranslateModule],
}) })
export class ProcessParametersComponent implements OnChanges { export class ProcessParametersComponent implements OnChanges, OnInit {
/** /**
* The currently selected script * The currently selected script
*/ */
@@ -59,7 +60,7 @@ export class ProcessParametersComponent implements OnChanges {
*/ */
parameterValues: ProcessParameter[]; parameterValues: ProcessParameter[];
ngOnInit() { ngOnInit(): void {
if (hasValue(this.initialParams)) { if (hasValue(this.initialParams)) {
this.parameterValues = this.initialParams; this.parameterValues = this.initialParams;
} }

View File

@@ -3,6 +3,7 @@ import {
Component, Component,
EventEmitter, EventEmitter,
Input, Input,
OnDestroy,
OnInit, OnInit,
Output, Output,
} from '@angular/core'; } from '@angular/core';
@@ -44,7 +45,7 @@ import { NotificationsService } from '../../shared/notifications/notifications.s
* Component for a user to edit their security information * Component for a user to edit their security information
* Displays a form containing a password field and a confirmation of the password * Displays a form containing a password field and a confirmation of the password
*/ */
export class ProfilePageSecurityFormComponent implements OnInit { export class ProfilePageSecurityFormComponent implements OnDestroy, OnInit {
/** /**
* Emits the validity of the password * Emits the validity of the password

View File

@@ -189,7 +189,6 @@ export const klaroConfiguration: any = {
purposes: ['registration-password-recovery'], purposes: ['registration-password-recovery'],
required: false, required: false,
cookies: [ cookies: [
[/^klaro-.+$/],
CAPTCHA_COOKIE, CAPTCHA_COOKIE,
], ],
onAccept: `window.refreshCaptchaScript?.call()`, onAccept: `window.refreshCaptchaScript?.call()`,

View File

@@ -8,6 +8,7 @@ import {
Component, Component,
Inject, Inject,
Injector, Injector,
OnInit,
} from '@angular/core'; } from '@angular/core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { import {
@@ -35,7 +36,7 @@ import { MenuService } from '../../../menu/menu.service';
standalone: true, standalone: true,
imports: [NgbDropdownModule, NgbTooltipModule, NgFor, NgIf, NgComponentOutlet, TranslateModule, AsyncPipe, DisabledDirective], imports: [NgbDropdownModule, NgbTooltipModule, NgFor, NgIf, NgComponentOutlet, TranslateModule, AsyncPipe, DisabledDirective],
}) })
export class DsoEditMenuExpandableSectionComponent extends MenuSectionComponent { export class DsoEditMenuExpandableSectionComponent extends MenuSectionComponent implements OnInit {
menuID: MenuID = MenuID.DSO_EDIT; menuID: MenuID = MenuID.DSO_EDIT;
itemModel; itemModel;

View File

@@ -1,6 +1,8 @@
import { import {
Component, Component,
Input, Input,
OnDestroy,
OnInit,
} from '@angular/core'; } from '@angular/core';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
@@ -15,7 +17,7 @@ import { AlertType } from '../alert/alert-type';
standalone: true, standalone: true,
imports: [AlertComponent], imports: [AlertComponent],
}) })
export class ErrorComponent { export class ErrorComponent implements OnDestroy, OnInit {
@Input() message = 'Error...'; @Input() message = 'Error...';
@@ -31,7 +33,7 @@ export class ErrorComponent {
} }
ngOnInit() { ngOnInit(): void {
if (this.message === undefined) { if (this.message === undefined) {
this.subscription = this.translate.get('error.default').subscribe((message: string) => { this.subscription = this.translate.get('error.default').subscribe((message: string) => {
this.message = message; this.message = message;
@@ -39,7 +41,7 @@ export class ErrorComponent {
} }
} }
ngOnDestroy() { ngOnDestroy(): void {
if (this.subscription !== undefined) { if (this.subscription !== undefined) {
this.subscription.unsubscribe(); this.subscription.unsubscribe();
} }

View File

@@ -6,11 +6,13 @@ import {
NgTemplateOutlet, NgTemplateOutlet,
} from '@angular/common'; } from '@angular/common';
import { import {
AfterViewInit,
ChangeDetectionStrategy, ChangeDetectionStrategy,
ChangeDetectorRef, ChangeDetectorRef,
Component, Component,
ComponentFactoryResolver, ComponentFactoryResolver,
ContentChildren, ContentChildren,
DoCheck,
EventEmitter, EventEmitter,
Inject, Inject,
Input, Input,
@@ -145,7 +147,8 @@ import { DsDynamicLookupRelationModalComponent } from './relation-lookup-modal/d
], ],
standalone: true, standalone: true,
}) })
export class DsDynamicFormControlContainerComponent extends DynamicFormControlContainerComponent implements OnInit, OnChanges, OnDestroy { export class DsDynamicFormControlContainerComponent extends DynamicFormControlContainerComponent
implements OnInit, OnChanges, OnDestroy, AfterViewInit, DoCheck {
@ContentChildren(DynamicTemplateDirective) contentTemplateList: QueryList<DynamicTemplateDirective>; @ContentChildren(DynamicTemplateDirective) contentTemplateList: QueryList<DynamicTemplateDirective>;
// eslint-disable-next-line @angular-eslint/no-input-rename // eslint-disable-next-line @angular-eslint/no-input-rename
@Input('templates') inputTemplateList: QueryList<DynamicTemplateDirective>; @Input('templates') inputTemplateList: QueryList<DynamicTemplateDirective>;

View File

@@ -9,6 +9,7 @@ import {
Component, Component,
EventEmitter, EventEmitter,
Input, Input,
OnDestroy,
OnInit, OnInit,
Output, Output,
ViewChild, ViewChild,
@@ -94,7 +95,7 @@ import { DynamicOneboxModel } from './dynamic-onebox.model';
], ],
standalone: true, standalone: true,
}) })
export class DsDynamicOneboxComponent extends DsDynamicVocabularyComponent implements OnInit { export class DsDynamicOneboxComponent extends DsDynamicVocabularyComponent implements OnDestroy, OnInit {
@Input() group: UntypedFormGroup; @Input() group: UntypedFormGroup;
@Input() model: DynamicOneboxModel; @Input() model: DynamicOneboxModel;

View File

@@ -6,6 +6,7 @@ import {
Component, Component,
EventEmitter, EventEmitter,
Input, Input,
OnInit,
Output, Output,
} from '@angular/core'; } from '@angular/core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
@@ -59,7 +60,7 @@ import { SearchResult } from '../../../../../search/models/search-result.model';
/** /**
* Tab for inside the lookup model that represents the currently selected relationships * Tab for inside the lookup model that represents the currently selected relationships
*/ */
export class DsDynamicLookupRelationSelectionTabComponent { export class DsDynamicLookupRelationSelectionTabComponent implements OnInit {
/** /**
* A string that describes the type of relationship * A string that describes the type of relationship
*/ */
@@ -122,7 +123,7 @@ export class DsDynamicLookupRelationSelectionTabComponent {
/** /**
* Set up the selection and pagination on load * Set up the selection and pagination on load
*/ */
ngOnInit() { ngOnInit(): void {
this.resetRoute(); this.resetRoute();
this.selectionRD$ = this.searchConfigService.paginatedSearchOptions this.selectionRD$ = this.searchConfigService.paginatedSearchOptions
.pipe( .pipe(

View File

@@ -4,6 +4,7 @@ import {
Component, Component,
EventEmitter, EventEmitter,
Input, Input,
OnChanges,
OnInit, OnInit,
Output, Output,
SimpleChanges, SimpleChanges,
@@ -38,7 +39,7 @@ import { isEmpty } from '../../empty.util';
standalone: true, standalone: true,
}) })
export class NumberPickerComponent implements OnInit, ControlValueAccessor { export class NumberPickerComponent implements OnChanges, OnInit, ControlValueAccessor {
@Input() id: string; @Input() id: string;
@Input() step: number; @Input() step: number;
@Input() min: number; @Input() min: number;

View File

@@ -5,6 +5,8 @@ import {
import { import {
Component, Component,
Input, Input,
OnDestroy,
OnInit,
} from '@angular/core'; } from '@angular/core';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { import {
@@ -35,7 +37,7 @@ import { AccessStatusObject } from './access-status.model';
/** /**
* Component rendering the access status of an item as a badge * Component rendering the access status of an item as a badge
*/ */
export class AccessStatusBadgeComponent { export class AccessStatusBadgeComponent implements OnDestroy, OnInit {
@Input() object: DSpaceObject; @Input() object: DSpaceObject;
accessStatus$: Observable<string>; accessStatus$: Observable<string>;

View File

@@ -1,4 +1,7 @@
import { Component } from '@angular/core'; import {
Component,
OnInit,
} from '@angular/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { find } from 'rxjs/operators'; import { find } from 'rxjs/operators';
import { Context } from 'src/app/core/shared/context.model'; import { Context } from 'src/app/core/shared/context.model';
@@ -29,7 +32,7 @@ import { SearchResultDetailElementComponent } from '../search-result-detail-elem
}) })
@listableObjectComponent(WorkflowItemSearchResult, ViewMode.DetailedListElement) @listableObjectComponent(WorkflowItemSearchResult, ViewMode.DetailedListElement)
export class WorkflowItemSearchResultDetailElementComponent extends SearchResultDetailElementComponent<WorkflowItemSearchResult, WorkflowItem> { export class WorkflowItemSearchResultDetailElementComponent extends SearchResultDetailElementComponent<WorkflowItemSearchResult, WorkflowItem> implements OnInit {
/** /**
* The item object that belonging to the result object * The item object that belonging to the result object
@@ -51,7 +54,7 @@ export class WorkflowItemSearchResultDetailElementComponent extends SearchResult
/** /**
* Initialize all instance variables * Initialize all instance variables
*/ */
ngOnInit() { ngOnInit(): void {
super.ngOnInit(); super.ngOnInit();
this.linkService.resolveLink(this.dso, followLink('item')); this.linkService.resolveLink(this.dso, followLink('item'));
this.initItem(this.dso.item as Observable<RemoteData<Item>>); this.initItem(this.dso.item as Observable<RemoteData<Item>>);

View File

@@ -1,4 +1,7 @@
import { Component } from '@angular/core'; import {
Component,
OnInit,
} from '@angular/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { find } from 'rxjs/operators'; import { find } from 'rxjs/operators';
@@ -29,7 +32,7 @@ import { SearchResultDetailElementComponent } from '../search-result-detail-elem
}) })
@listableObjectComponent(WorkspaceItemSearchResult, ViewMode.DetailedListElement) @listableObjectComponent(WorkspaceItemSearchResult, ViewMode.DetailedListElement)
export class WorkspaceItemSearchResultDetailElementComponent extends SearchResultDetailElementComponent<WorkspaceItemSearchResult, WorkspaceItem> { export class WorkspaceItemSearchResultDetailElementComponent extends SearchResultDetailElementComponent<WorkspaceItemSearchResult, WorkspaceItem> implements OnInit {
/** /**
* The item object that belonging to the result object * The item object that belonging to the result object
@@ -51,7 +54,7 @@ export class WorkspaceItemSearchResultDetailElementComponent extends SearchResul
/** /**
* Initialize all instance variables * Initialize all instance variables
*/ */
ngOnInit() { ngOnInit(): void {
super.ngOnInit(); super.ngOnInit();
this.linkService.resolveLink(this.dso, followLink('item')); this.linkService.resolveLink(this.dso, followLink('item'));
this.initItem(this.dso.item as Observable<RemoteData<Item>>); this.initItem(this.dso.item as Observable<RemoteData<Item>>);

View File

@@ -3,7 +3,10 @@ import {
NgFor, NgFor,
NgIf, NgIf,
} from '@angular/common'; } from '@angular/common';
import { Component } from '@angular/core'; import {
Component,
OnInit,
} from '@angular/core';
import { RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
@@ -35,7 +38,7 @@ import { SearchResultGridElementComponent } from '../../search-result-grid-eleme
/** /**
* The component for displaying a grid element for an item search result of the type Publication * The component for displaying a grid element for an item search result of the type Publication
*/ */
export class ItemSearchResultGridElementComponent extends SearchResultGridElementComponent<ItemSearchResult, Item> { export class ItemSearchResultGridElementComponent extends SearchResultGridElementComponent<ItemSearchResult, Item> implements OnInit {
/** /**
* Route to the item's page * Route to the item's page
*/ */

View File

@@ -5,6 +5,7 @@ import {
import { import {
Component, Component,
Input, Input,
OnInit,
} from '@angular/core'; } from '@angular/core';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
@@ -28,7 +29,7 @@ import { IdentifierData } from './identifier-data.model';
/** /**
* Component rendering an identifier, eg. DOI or handle * Component rendering an identifier, eg. DOI or handle
*/ */
export class IdentifierDataComponent { export class IdentifierDataComponent implements OnInit {
@Input() item: Item; @Input() item: Item;
identifiers$: Observable<IdentifierData>; identifiers$: Observable<IdentifierData>;

View File

@@ -5,6 +5,7 @@ import {
import { import {
Component, Component,
Inject, Inject,
OnInit,
} from '@angular/core'; } from '@angular/core';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
@@ -40,7 +41,7 @@ import { ThemedItemListPreviewComponent } from '../../item-list-preview/themed-i
imports: [NgIf, ThemedItemListPreviewComponent, AsyncPipe, TranslateModule, VarDirective], imports: [NgIf, ThemedItemListPreviewComponent, AsyncPipe, TranslateModule, VarDirective],
}) })
@listableObjectComponent(ClaimedApprovedTaskSearchResult, ViewMode.ListElement) @listableObjectComponent(ClaimedApprovedTaskSearchResult, ViewMode.ListElement)
export class ClaimedApprovedSearchResultListElementComponent extends SearchResultListElementComponent<ClaimedTaskSearchResult, ClaimedTask> { export class ClaimedApprovedSearchResultListElementComponent extends SearchResultListElementComponent<ClaimedTaskSearchResult, ClaimedTask> implements OnInit {
/** /**
* A boolean representing if to show submitter information * A boolean representing if to show submitter information
@@ -69,7 +70,7 @@ export class ClaimedApprovedSearchResultListElementComponent extends SearchResul
/** /**
* Initialize all instance variables * Initialize all instance variables
*/ */
ngOnInit() { ngOnInit(): void {
super.ngOnInit(); super.ngOnInit();
this.linkService.resolveLinks(this.dso, this.linkService.resolveLinks(this.dso,
followLink('workflowitem', followLink('workflowitem',

View File

@@ -5,6 +5,7 @@ import {
import { import {
Component, Component,
Inject, Inject,
OnInit,
} from '@angular/core'; } from '@angular/core';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
@@ -40,7 +41,7 @@ import { ThemedItemListPreviewComponent } from '../../item-list-preview/themed-i
imports: [NgIf, ThemedItemListPreviewComponent, AsyncPipe, TranslateModule, VarDirective], imports: [NgIf, ThemedItemListPreviewComponent, AsyncPipe, TranslateModule, VarDirective],
}) })
@listableObjectComponent(ClaimedDeclinedTaskSearchResult, ViewMode.ListElement) @listableObjectComponent(ClaimedDeclinedTaskSearchResult, ViewMode.ListElement)
export class ClaimedDeclinedSearchResultListElementComponent extends SearchResultListElementComponent<ClaimedTaskSearchResult, ClaimedTask> { export class ClaimedDeclinedSearchResultListElementComponent extends SearchResultListElementComponent<ClaimedTaskSearchResult, ClaimedTask> implements OnInit {
/** /**
* A boolean representing if to show submitter information * A boolean representing if to show submitter information
@@ -69,7 +70,7 @@ export class ClaimedDeclinedSearchResultListElementComponent extends SearchResul
/** /**
* Initialize all instance variables * Initialize all instance variables
*/ */
ngOnInit() { ngOnInit(): void {
super.ngOnInit(); super.ngOnInit();
this.linkService.resolveLinks(this.dso, this.linkService.resolveLinks(this.dso,
followLink('workflowitem', followLink('workflowitem',

View File

@@ -6,6 +6,7 @@ import {
import { import {
Component, Component,
Inject, Inject,
OnInit,
} from '@angular/core'; } from '@angular/core';
import { BehaviorSubject } from 'rxjs'; import { BehaviorSubject } from 'rxjs';
@@ -43,7 +44,7 @@ import { SearchResultListElementComponent } from '../../search-result-list-eleme
}) })
@listableObjectComponent(WorkflowItemSearchResult, ViewMode.ListElement) @listableObjectComponent(WorkflowItemSearchResult, ViewMode.ListElement)
export class WorkflowItemSearchResultListElementComponent extends SearchResultListElementComponent<WorkflowItemSearchResult, WorkflowItem> { export class WorkflowItemSearchResultListElementComponent extends SearchResultListElementComponent<WorkflowItemSearchResult, WorkflowItem> implements OnInit {
LinkTypes = CollectionElementLinkType; LinkTypes = CollectionElementLinkType;
ViewModes = ViewMode; ViewModes = ViewMode;
@@ -75,7 +76,7 @@ export class WorkflowItemSearchResultListElementComponent extends SearchResultLi
/** /**
* Initialize all instance variables * Initialize all instance variables
*/ */
ngOnInit() { ngOnInit(): void {
super.ngOnInit(); super.ngOnInit();
this.deriveSearchResult(); this.deriveSearchResult();
this.showThumbnails = this.appConfig.browseBy.showThumbnails; this.showThumbnails = this.appConfig.browseBy.showThumbnails;

View File

@@ -6,6 +6,7 @@ import {
import { import {
Component, Component,
Inject, Inject,
OnInit,
} from '@angular/core'; } from '@angular/core';
import { BehaviorSubject } from 'rxjs'; import { BehaviorSubject } from 'rxjs';
@@ -43,7 +44,7 @@ import { SearchResultListElementComponent } from '../../search-result-list-eleme
}) })
@listableObjectComponent(WorkspaceItemSearchResult, ViewMode.ListElement) @listableObjectComponent(WorkspaceItemSearchResult, ViewMode.ListElement)
export class WorkspaceItemSearchResultListElementComponent extends SearchResultListElementComponent<WorkspaceItemSearchResult, WorkspaceItem> { export class WorkspaceItemSearchResultListElementComponent extends SearchResultListElementComponent<WorkspaceItemSearchResult, WorkspaceItem> implements OnInit {
LinkTypes = CollectionElementLinkType; LinkTypes = CollectionElementLinkType;
ViewModes = ViewMode; ViewModes = ViewMode;
@@ -75,7 +76,7 @@ export class WorkspaceItemSearchResultListElementComponent extends SearchResult
/** /**
* Initialize all instance variables * Initialize all instance variables
*/ */
ngOnInit() { ngOnInit(): void {
super.ngOnInit(); super.ngOnInit();
this.deriveSearchResult(); this.deriveSearchResult();
this.showThumbnails = this.appConfig.browseBy.showThumbnails; this.showThumbnails = this.appConfig.browseBy.showThumbnails;

View File

@@ -2,7 +2,10 @@ import {
NgClass, NgClass,
NgIf, NgIf,
} from '@angular/common'; } from '@angular/common';
import { Component } from '@angular/core'; import {
Component,
OnInit,
} from '@angular/core';
import { RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { Collection } from '../../../../core/shared/collection.model'; import { Collection } from '../../../../core/shared/collection.model';
@@ -23,7 +26,7 @@ import { SearchResultListElementComponent } from '../search-result-list-element.
* Component representing a collection search result in list view * Component representing a collection search result in list view
*/ */
@listableObjectComponent(CollectionSearchResult, ViewMode.ListElement) @listableObjectComponent(CollectionSearchResult, ViewMode.ListElement)
export class CollectionSearchResultListElementComponent extends SearchResultListElementComponent<CollectionSearchResult, Collection> { export class CollectionSearchResultListElementComponent extends SearchResultListElementComponent<CollectionSearchResult, Collection> implements OnInit {
/** /**
* Display thumbnails if required by configuration * Display thumbnails if required by configuration

View File

@@ -2,7 +2,10 @@ import {
NgClass, NgClass,
NgIf, NgIf,
} from '@angular/common'; } from '@angular/common';
import { Component } from '@angular/core'; import {
Component,
OnInit,
} from '@angular/core';
import { RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { Community } from '../../../../core/shared/community.model'; import { Community } from '../../../../core/shared/community.model';
@@ -23,13 +26,12 @@ import { SearchResultListElementComponent } from '../search-result-list-element.
* Component representing a community search result in list view * Component representing a community search result in list view
*/ */
@listableObjectComponent(CommunitySearchResult, ViewMode.ListElement) @listableObjectComponent(CommunitySearchResult, ViewMode.ListElement)
export class CommunitySearchResultListElementComponent extends SearchResultListElementComponent<CommunitySearchResult, Community> { export class CommunitySearchResultListElementComponent extends SearchResultListElementComponent<CommunitySearchResult, Community> implements OnInit {
/** /**
* Display thumbnails if required by configuration * Display thumbnails if required by configuration
*/ */
showThumbnails: boolean; showThumbnails: boolean;
ngOnInit(): void { ngOnInit(): void {
super.ngOnInit(); super.ngOnInit();
this.showThumbnails = this.showThumbnails ?? this.appConfig.browseBy.showThumbnails; this.showThumbnails = this.showThumbnails ?? this.appConfig.browseBy.showThumbnails;

View File

@@ -4,7 +4,10 @@ import {
NgFor, NgFor,
NgIf, NgIf,
} from '@angular/common'; } from '@angular/common';
import { Component } from '@angular/core'; import {
Component,
OnInit,
} from '@angular/core';
import { RouterLink } from '@angular/router'; import { RouterLink } from '@angular/router';
import { Item } from '../../../../../../core/shared/item.model'; import { Item } from '../../../../../../core/shared/item.model';
@@ -30,7 +33,7 @@ import { SearchResultListElementComponent } from '../../../search-result-list-el
/** /**
* The component for displaying a list element for an item search result of the type Publication * The component for displaying a list element for an item search result of the type Publication
*/ */
export class ItemSearchResultListElementComponent extends SearchResultListElementComponent<ItemSearchResult, Item> { export class ItemSearchResultListElementComponent extends SearchResultListElementComponent<ItemSearchResult, Item> implements OnInit {
/** /**
* Route to the item's page * Route to the item's page
*/ */

View File

@@ -3,7 +3,10 @@ import {
NgClass, NgClass,
NgIf, NgIf,
} from '@angular/common'; } from '@angular/common';
import { Component } from '@angular/core'; import {
Component,
OnInit,
} from '@angular/core';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { import {
Observable, Observable,
@@ -41,7 +44,7 @@ import { SearchResultListElementComponent } from '../search-result-list-element/
* It displays the name of the parent, title and description of the object. All of which are customizable in the child * It displays the name of the parent, title and description of the object. All of which are customizable in the child
* component by overriding the relevant methods of this component * component by overriding the relevant methods of this component
*/ */
export class SidebarSearchListElementComponent<T extends SearchResult<K>, K extends DSpaceObject> extends SearchResultListElementComponent<T, K> { export class SidebarSearchListElementComponent<T extends SearchResult<K>, K extends DSpaceObject> extends SearchResultListElementComponent<T, K> implements OnInit {
/** /**
* Observable for the title of the parent object (displayed above the object's title) * Observable for the title of the parent object (displayed above the object's title)
*/ */

View File

@@ -7,6 +7,7 @@ import {
ElementRef, ElementRef,
EventEmitter, EventEmitter,
OnDestroy, OnDestroy,
OnInit,
Output, Output,
ViewChild, ViewChild,
} from '@angular/core'; } from '@angular/core';
@@ -65,7 +66,7 @@ export const compareArraysUsingFieldUuids = () =>
selector: 'ds-paginated-drag-drop-abstract', selector: 'ds-paginated-drag-drop-abstract',
template: '', template: '',
}) })
export abstract class AbstractPaginatedDragAndDropListComponent<T extends DSpaceObject> implements OnDestroy { export abstract class AbstractPaginatedDragAndDropListComponent<T extends DSpaceObject> implements OnInit, OnDestroy {
/** /**
* A view on the child pagination component * A view on the child pagination component
*/ */
@@ -142,7 +143,7 @@ export abstract class AbstractPaginatedDragAndDropListComponent<T extends DSpace
/** /**
* Initialize the observables * Initialize the observables
*/ */
ngOnInit() { ngOnInit(): void {
this.initializeObjectsRD(); this.initializeObjectsRD();
this.initializeURL(); this.initializeURL();
this.initializeUpdates(); this.initializeUpdates();

View File

@@ -8,7 +8,7 @@
{{'search.filters.filter.' + filterConfig.name + '.min.label' | translate}} {{'search.filters.filter.' + filterConfig.name + '.min.label' | translate}}
</span> </span>
<input type="text" [(ngModel)]="range[0]" [name]="filterConfig.paramName + '.min'" <input type="text" [(ngModel)]="range[0]" [name]="filterConfig.paramName + '.min'"
class="form-control" (blur)="onSubmit()" class="form-control"
[attr.aria-label]="minLabel" [attr.aria-label]="minLabel"
[placeholder]="minLabel" [placeholder]="minLabel"
/> />
@@ -20,7 +20,7 @@
{{'search.filters.filter.' + filterConfig.name + '.max.label' | translate}} {{'search.filters.filter.' + filterConfig.name + '.max.label' | translate}}
</span> </span>
<input type="text" [(ngModel)]="range[1]" [name]="filterConfig.paramName + '.max'" <input type="text" [(ngModel)]="range[1]" [name]="filterConfig.paramName + '.max'"
class="form-control" (blur)="onSubmit()" class="form-control"
[attr.aria-label]="maxLabel" [attr.aria-label]="maxLabel"
[placeholder]="maxLabel" [placeholder]="maxLabel"
/> />
@@ -33,7 +33,8 @@
<ng-container *ngIf="shouldShowSlider()"> <ng-container *ngIf="shouldShowSlider()">
<nouislider [connect]="true" [config]="config" [min]="min" [max]="max" [step]="1" <nouislider [connect]="true" [config]="config" [min]="min" [max]="max" [step]="1"
[dsDebounce]="250" (onDebounce)="onSubmit()" [dsDebounce]="250"
(change)="onSliderChange($event)"
(keydown)="startKeyboardControl()" (keyup)="stopKeyboardControl()" (keydown)="startKeyboardControl()" (keyup)="stopKeyboardControl()"
[(ngModel)]="range" ngDefaultControl> [(ngModel)]="range" ngDefaultControl>
</nouislider> </nouislider>
@@ -43,5 +44,8 @@
<ds-search-facet-range-option *ngFor="let value of page.page; trackBy: trackUpdate" [filterConfig]="filterConfig" [filterValue]="value" [inPlaceSearch]="inPlaceSearch"></ds-search-facet-range-option> <ds-search-facet-range-option *ngFor="let value of page.page; trackBy: trackUpdate" [filterConfig]="filterConfig" [filterValue]="value" [inPlaceSearch]="inPlaceSearch"></ds-search-facet-range-option>
</div> </div>
</ng-container> </ng-container>
<button (click)="onSubmit()" class="btn btn-primary">
{{'search.filters.search.submit' | translate}}
</button>
</div> </div>
</div> </div>

View File

@@ -91,6 +91,11 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple
*/ */
range: [number | undefined, number | undefined]; range: [number | undefined, number | undefined];
/**
* The range currently selected by the slider
*/
sliderRange: [number | undefined, number | undefined];
/** /**
* Whether the sider is being controlled by the keyboard. * Whether the sider is being controlled by the keyboard.
* Supresses any changes until the key is released. * Supresses any changes until the key is released.
@@ -145,6 +150,15 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple
}; };
} }
/**
* Updates the sliderRange property with the current slider range.
* This method is called whenever the slider value changes, but it does not immediately apply the changes.
* @param range - The current range selected by the slider
*/
onSliderChange(range: [number | undefined, number | undefined]): void {
this.sliderRange = range;
}
/** /**
* Submits new custom range values to the range filter from the widget * Submits new custom range values to the range filter from the widget
*/ */
@@ -182,5 +196,4 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple
shouldShowSlider(): boolean { shouldShowSlider(): boolean {
return isPlatformBrowser(this.platformId); return isPlatformBrowser(this.platformId);
} }
} }

View File

@@ -19,9 +19,9 @@
<span><i class="fas fa-cloud-upload" <span><i class="fas fa-cloud-upload"
aria-hidden="true"></i> {{ ((fileObject === null || fileObject === undefined) ? dropMessageLabel : dropMessageLabelReplacement) | translate}} {{'uploader.or' | translate}}</span> aria-hidden="true"></i> {{ ((fileObject === null || fileObject === undefined) ? dropMessageLabel : dropMessageLabelReplacement) | translate}} {{'uploader.or' | translate}}</span>
<label class="btn btn-link m-0 p-0 ml-1"> <label class="btn btn-link m-0 p-0 ml-1">
<input class="form-control-file d-none" requireFile #file="ngModel" type="file" name="file-upload" <input class="form-control-file d-none" type="file" name="file-upload"
id="file-upload" id="file-upload"
[ngModel]="fileObject" (ngModelChange)="setFile($event)"> (change)="handleFileInput($event)">
{{'uploader.browse' | translate}} {{'uploader.browse' | translate}}
</label> </label>
</p> </p>

View File

@@ -54,7 +54,7 @@ export class FileDropzoneNoUploaderComponent implements OnInit {
/** /**
* The function to call when file is added * The function to call when file is added
*/ */
@Output() onFileAdded: EventEmitter<any> = new EventEmitter<any>(); @Output() onFileAdded: EventEmitter<File> = new EventEmitter<File>();
/** /**
* The uploader configuration options * The uploader configuration options
@@ -83,15 +83,17 @@ export class FileDropzoneNoUploaderComponent implements OnInit {
} }
@HostListener('window:drop', ['$event']) @HostListener('window:drop', ['$event'])
onDrop(event: any) { onDrop(event: DragEvent) {
event.preventDefault(); event.preventDefault();
event.stopPropagation();
} }
@HostListener('window:dragover', ['$event']) @HostListener('window:dragover', ['$event'])
onDragOver(event: any) { onDragOver(event: DragEvent) {
// Show drop area on the page // Show drop area on the page
event.preventDefault(); event.preventDefault();
if ((event.target as any).tagName !== 'HTML') { event.stopPropagation();
if ((event.target as HTMLElement).tagName !== 'HTML') {
this.isOverDocumentDropZone = observableOf(true); this.isOverDocumentDropZone = observableOf(true);
} }
} }
@@ -105,11 +107,18 @@ export class FileDropzoneNoUploaderComponent implements OnInit {
} }
} }
public handleFileInput(event: Event) {
const input = event.target as HTMLInputElement;
if (input.files && input.files.length > 0) {
this.setFile(input.files);
}
}
/** /**
* Set file * Set file
* @param files * @param files
*/ */
setFile(files) { public setFile(files: FileList) {
this.fileObject = files.length > 0 ? files[0] : undefined; this.fileObject = files.length > 0 ? files[0] : undefined;
this.onFileAdded.emit(this.fileObject); this.onFileAdded.emit(this.fileObject);
} }

View File

@@ -6,10 +6,16 @@
top: 0; top: 0;
left: 0; left: 0;
z-index: -1; z-index: -1;
display: block;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s ease;
} }
.ds-document-drop-zone-active { .ds-document-drop-zone-active {
z-index: var(--ds-drop-zone-area-z-index) !important; z-index: var(--ds-drop-zone-area-z-index) !important;
opacity: 1;
visibility: visible;
} }
.ds-document-drop-zone-inner { .ds-document-drop-zone-inner {

View File

@@ -1,12 +1,14 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { HttpXsrfTokenExtractor } from '@angular/common/http'; import { HttpXsrfTokenExtractor } from '@angular/common/http';
import { import {
AfterViewInit,
ChangeDetectionStrategy, ChangeDetectionStrategy,
ChangeDetectorRef, ChangeDetectorRef,
Component, Component,
EventEmitter, EventEmitter,
HostListener, HostListener,
Input, Input,
OnInit,
Output, Output,
ViewEncapsulation, ViewEncapsulation,
} from '@angular/core'; } from '@angular/core';
@@ -43,7 +45,7 @@ import { UploaderProperties } from './uploader-properties.model';
standalone: true, standalone: true,
imports: [TranslateModule, FileUploadModule, CommonModule, DisabledDirective], imports: [TranslateModule, FileUploadModule, CommonModule, DisabledDirective],
}) })
export class UploaderComponent { export class UploaderComponent implements OnInit, AfterViewInit {
/** /**
* The message to show when drag files on the drop zone * The message to show when drag files on the drop zone
@@ -123,7 +125,7 @@ export class UploaderComponent {
/** /**
* Method provided by Angular. Invoked after the constructor. * Method provided by Angular. Invoked after the constructor.
*/ */
ngOnInit() { ngOnInit(): void {
this.uploaderId = 'ds-drag-and-drop-uploader' + uniqueId(); this.uploaderId = 'ds-drag-and-drop-uploader' + uniqueId();
this.checkConfig(this.uploadFilesOptions); this.checkConfig(this.uploadFilesOptions);
this.uploader = new FileUploader({ this.uploader = new FileUploader({
@@ -148,7 +150,7 @@ export class UploaderComponent {
} }
} }
ngAfterViewInit() { ngAfterViewInit(): void {
this.uploader.onAfterAddingAll = ((items) => { this.uploader.onAfterAddingAll = ((items) => {
this.onFileSelected.emit(items); this.onFileSelected.emit(items);
}); });

View File

@@ -55,30 +55,40 @@ export class MarkdownDirective implements OnInit, OnDestroy {
async render(value: string, forcePreview = false): Promise<SafeHtml> { async render(value: string, forcePreview = false): Promise<SafeHtml> {
if (isEmpty(value) || (!environment.markdown.enabled && !forcePreview)) { if (isEmpty(value) || (!environment.markdown.enabled && !forcePreview)) {
return value; this.el.innerHTML = value;
return;
} else {
if (environment.markdown.mathjax) {
this.renderMathjaxThenMarkdown(value);
} else {
this.renderMarkdown(value);
}
} }
}
private renderMathjaxThenMarkdown(value: string) {
const sanitized = this.sanitizer.sanitize(SecurityContext.HTML, value);
this.el.innerHTML = sanitized;
this.mathService.ready().pipe(
filter((ready) => ready),
take(1),
takeUntil(this.alive$),
).subscribe(() => {
this.mathService.render(this.el)?.then(_ => {
this.renderMarkdown(this.el.innerHTML, true);
});
});
}
private async renderMarkdown(value: string, alreadySanitized = false) {
const MarkdownIt = await this.markdownIt; const MarkdownIt = await this.markdownIt;
const md = new MarkdownIt({ const md = new MarkdownIt({
html: true, html: true,
linkify: true, linkify: true,
}); });
const html = this.sanitizer.sanitize(SecurityContext.HTML, md.render(value)); const html = alreadySanitized ? md.render(value) : this.sanitizer.sanitize(SecurityContext.HTML, md.render(value));
this.el.innerHTML = html; this.el.innerHTML = html;
if (environment.markdown.mathjax) {
this.renderMathjax();
}
}
private renderMathjax() {
this.mathService.ready().pipe(
filter((ready) => ready),
take(1),
takeUntil(this.alive$),
).subscribe(() => {
this.mathService.render(this.el);
});
} }
ngOnDestroy() { ngOnDestroy() {

View File

@@ -5,6 +5,7 @@ import {
EventEmitter, EventEmitter,
Input, Input,
OnChanges, OnChanges,
OnDestroy,
OnInit, OnInit,
Output, Output,
SimpleChanges, SimpleChanges,
@@ -60,7 +61,7 @@ import { SubmissionService } from '../../submission.service';
DisabledDirective, DisabledDirective,
], ],
}) })
export class SubmissionFormCollectionComponent implements OnChanges, OnInit { export class SubmissionFormCollectionComponent implements OnDestroy, OnChanges, OnInit {
/** /**
* The current collection id this submission belonging to * The current collection id this submission belonging to

View File

@@ -3,6 +3,7 @@ import {
Component, Component,
Input, Input,
OnChanges, OnChanges,
OnDestroy,
} from '@angular/core'; } from '@angular/core';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { import {
@@ -43,7 +44,7 @@ import parseSectionErrors from '../../utils/parseSectionErrors';
], ],
standalone: true, standalone: true,
}) })
export class SubmissionUploadFilesComponent implements OnChanges { export class SubmissionUploadFilesComponent implements OnChanges, OnDestroy {
/** /**
* The collection id this submission belonging to * The collection id this submission belonging to

View File

@@ -7,6 +7,7 @@ import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
Component, Component,
Inject, Inject,
OnInit,
} from '@angular/core'; } from '@angular/core';
import { import {
TranslateModule, TranslateModule,
@@ -48,7 +49,7 @@ import { SectionsService } from '../sections.service';
standalone: true, standalone: true,
}) })
export class SubmissionSectionDuplicatesComponent extends SectionModelComponent { export class SubmissionSectionDuplicatesComponent extends SectionModelComponent implements OnInit {
protected readonly Metadata = Metadata; protected readonly Metadata = Metadata;
/** /**
* The Alert categories. * The Alert categories.

View File

@@ -7,6 +7,7 @@ import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
Component, Component,
Inject, Inject,
OnInit,
} from '@angular/core'; } from '@angular/core';
import { import {
TranslateModule, TranslateModule,
@@ -47,7 +48,7 @@ import { SectionsService } from '../sections.service';
standalone: true, standalone: true,
}) })
export class SubmissionSectionIdentifiersComponent extends SectionModelComponent { export class SubmissionSectionIdentifiersComponent extends SectionModelComponent implements OnInit {
/** /**
* The Alert categories. * The Alert categories.
* @type {AlertType} * @type {AlertType}
@@ -76,7 +77,6 @@ export class SubmissionSectionIdentifiersComponent extends SectionModelComponent
/** /**
* Initialize instance variables. * Initialize instance variables.
* *
* @param {PaginationService} paginationService
* @param {TranslateService} translate * @param {TranslateService} translate
* @param {SectionsService} sectionService * @param {SectionsService} sectionService
* @param {SubmissionService} submissionService * @param {SubmissionService} submissionService
@@ -93,7 +93,7 @@ export class SubmissionSectionIdentifiersComponent extends SectionModelComponent
super(injectedCollectionId, injectedSectionData, injectedSubmissionId); super(injectedCollectionId, injectedSectionData, injectedSubmissionId);
} }
ngOnInit() { ngOnInit(): void {
super.ngOnInit(); super.ngOnInit();
} }

View File

@@ -50,16 +50,6 @@ export const ROUTES: Route[] = [
}, },
data: { title: 'workspace-item.delete', breadcrumbKey: 'workspace-item.delete' }, data: { title: 'workspace-item.delete', breadcrumbKey: 'workspace-item.delete' },
}, },
{
canActivate: [authenticatedGuard],
path: 'delete',
component: ThemedWorkspaceItemsDeletePageComponent,
resolve: {
dso: itemFromWorkspaceResolver,
breadcrumb: i18nBreadcrumbResolver,
},
data: { title: 'workspace-item.delete', breadcrumbKey: 'workspace-item.delete' },
},
], ],
}, },
]; ];

View File

@@ -5881,7 +5881,7 @@
"workflow-item.delete.notification.success.title": "Gelöscht", "workflow-item.delete.notification.success.title": "Gelöscht",
// "workflow-item.delete.notification.success.content": "This workflow item was successfully deleted", // "workflow-item.delete.notification.success.content": "This workflow item was successfully deleted",
"workflow-item.delete.notification.success.content": "Dieses Workflow-Item wurde gelöscht.", "workflow-item.delete.notification.success.content": "Dieses Workflow-Item wurde erfolgreich gelöscht.",
// "workflow-item.delete.notification.error.title": "Something went wrong", // "workflow-item.delete.notification.error.title": "Something went wrong",
"workflow-item.delete.notification.error.title": "Das hat leider nicht funktioniert.", "workflow-item.delete.notification.error.title": "Das hat leider nicht funktioniert.",
@@ -5926,4 +5926,36 @@
// "workflow-item.send-back.button.confirm": "Send back" // "workflow-item.send-back.button.confirm": "Send back"
"workflow-item.send-back.button.confirm": "Zurücksenden", "workflow-item.send-back.button.confirm": "Zurücksenden",
// "workflow-item.view.breadcrumbs": "Workflow View",
"workflow-item.view.breadcrumbs": "Workflow-Ansicht",
// "workspace-item.view.breadcrumbs": "Workspace View",
"workspace-item.view.breadcrumbs": "Workspace-Ansicht",
// "workspace-item.view.title": "Workspace View",
"workspace-item.view.title": "Workspace-Ansicht",
// "workspace-item.delete.breadcrumbs": "Workspace Delete",
"workspace-item.delete.breadcrumbs": "Workspace-Item löschen",
// "workspace-item.delete.header": "Delete workspace item",
"workspace-item.delete.header": "Workspace-Item löschen",
// "workspace-item.delete.button.confirm": "Delete",
"workspace-item.delete.button.confirm": "Löschen",
// "workspace-item.delete.button.cancel": "Cancel",
"workspace-item.delete.button.cancel": "Abbrechen",
// "workspace-item.delete.notification.success.title": "Deleted",
"workspace-item.delete.notification.success.title": "Gelöscht",
// "workspace-item.delete.title": "This workspace item was successfully deleted",
"workspace-item.delete.title": "Dieses Workspace-Item wurde erfolgreich gelöscht.",
// "workspace-item.delete.notification.error.title": "Something went wrong",
"workspace-item.delete.notification.error.title": "Das hat leider nicht funktioniert.",
// "workspace-item.delete.notification.error.content": "The workspace item could not be deleted",
"workspace-item.delete.notification.error.content": "Das Workspace-Item konnte nicht gelöscht werden.",
} }

View File

@@ -6386,10 +6386,10 @@
"submission.workflow.tasks.pool.show-detail": "Afficher le détail", "submission.workflow.tasks.pool.show-detail": "Afficher le détail",
// "submission.workspace.generic.view": "View", // "submission.workspace.generic.view": "View",
"submission.workspace.generic.view": "Voir", "submission.workspace.generic.view": "Afficher",
// "submission.workspace.generic.view-help": "Select this option to view the item's metadata.", // "submission.workspace.generic.view-help": "Select this option to view the item's metadata.",
"submission.workspace.generic.view-help": "Sélectionner cette option pour voir les métadonnées de l'item.", "submission.workspace.generic.view-help": "Sélectionner cette option pour afficher les métadonnées de l'item.",
// "thumbnail.default.alt": "Thumbnail Image", // "thumbnail.default.alt": "Thumbnail Image",
"thumbnail.default.alt": "Vignette d'image", "thumbnail.default.alt": "Vignette d'image",