diff --git a/config/config.example.yml b/config/config.example.yml
index 2cb8f9541be..21629f66d20 100644
--- a/config/config.example.yml
+++ b/config/config.example.yml
@@ -431,6 +431,8 @@ item:
pageSize: 5
# Show the bitstream access status label on the item page
showAccessStatuses: false
+ # Open bitstream download links in a new browser tab by default
+ openDownloadLinksInNewTab: false
# Configuration of metadata to be displayed in the item metadata link view popover
metadataLinkViewPopoverData:
# Metdadata list to be displayed for entities without a specific configuration
diff --git a/src/app/shared/bitstream-attachment/attachment-render/types/file-download-button/file-download-button.component.html b/src/app/shared/bitstream-attachment/attachment-render/types/file-download-button/file-download-button.component.html
index 366996ee1f0..8eb3c85f732 100644
--- a/src/app/shared/bitstream-attachment/attachment-render/types/file-download-button/file-download-button.component.html
+++ b/src/app/shared/bitstream-attachment/attachment-render/types/file-download-button/file-download-button.component.html
@@ -1,18 +1,21 @@
@if (!hasNoDownload) {
@if (bitstreamPath$ | async; as bitstreamLink) {
@if (canDownload$ | async) {
-
+
} @else {
-
+
}
}
}
diff --git a/src/app/shared/file-download-link/file-download-link.component.spec.ts b/src/app/shared/file-download-link/file-download-link.component.spec.ts
index 453ac868a4c..32232c30bd1 100644
--- a/src/app/shared/file-download-link/file-download-link.component.spec.ts
+++ b/src/app/shared/file-download-link/file-download-link.component.spec.ts
@@ -43,6 +43,19 @@ describe('FileDownloadLinkComponent', () => {
let item: Item;
let storeMock: any;
+ const mockAppConfig = {
+ cache: {
+ msToLive: {
+ default: 15 * 60 * 1000,
+ },
+ },
+ item: {
+ bitstream: {
+ openDownloadLinksInNewTab: true,
+ },
+ },
+ };
+
const itemRequestStub = Object.assign(new ItemRequest(), {
token: 'item-request-token',
requestName: 'requester name',
@@ -88,7 +101,7 @@ describe('FileDownloadLinkComponent', () => {
{ provide: ActivatedRoute, useValue: activatedRoute },
{ provide: Store, useValue: storeMock },
{ provide: APP_DATA_SERVICES_MAP, useValue: {} },
- { provide: APP_CONFIG, useValue: { cache: { msToLive: { default: 15 * 60 * 1000 } } } },
+ { provide: APP_CONFIG, useValue: mockAppConfig },
],
})
.overrideComponent(FileDownloadLinkComponent, {
@@ -129,9 +142,19 @@ describe('FileDownloadLinkComponent', () => {
fixture.detectChanges();
const link = fixture.debugElement.query(By.css('a'));
expect(link.injector.get(RouterLinkDirectiveStub).routerLink).toContain(new URLCombiner(getBitstreamModuleRoute(), bitstream.uuid, 'download').toString());
+ expect(link.nativeElement.getAttribute('target')).toBe('_blank');
const lock = fixture.debugElement.query(By.css('.fa-lock'));
expect(lock).toBeNull();
});
+
+ it('should keep an explicit isBlank input over the config default', () => {
+ component.isBlank = false;
+ component.ngOnInit();
+ scheduler.flush();
+ fixture.detectChanges();
+ const link = fixture.debugElement.query(By.css('a'));
+ expect(link.nativeElement.getAttribute('target')).toBe('_self');
+ });
});
describe('when the user has no download rights but has the right to request a copy', () => {
diff --git a/src/app/shared/file-download-link/file-download-link.component.ts b/src/app/shared/file-download-link/file-download-link.component.ts
index f6ddbcf230e..a3de3103e44 100644
--- a/src/app/shared/file-download-link/file-download-link.component.ts
+++ b/src/app/shared/file-download-link/file-download-link.component.ts
@@ -5,13 +5,19 @@ import {
} from '@angular/common';
import {
Component,
+ Inject,
Input,
OnInit,
+ Optional,
} from '@angular/core';
import {
ActivatedRoute,
RouterLink,
} from '@angular/router';
+import {
+ APP_CONFIG,
+ AppConfig,
+} from '@dspace/config/app-config.interface';
import { DSONameService } from '@dspace/core/breadcrumbs/dso-name.service';
import { AuthorizationDataService } from '@dspace/core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '@dspace/core/data/feature-authorization/feature-id';
@@ -78,7 +84,7 @@ export class FileDownloadLinkComponent implements OnInit {
/**
* A boolean representing if link is shown in same tab or in a new one.
*/
- @Input() isBlank = false;
+ @Input() isBlank: boolean;
@Input() enableRequestACopy = true;
@@ -108,10 +114,13 @@ export class FileDownloadLinkComponent implements OnInit {
public dsoNameService: DSONameService,
private route: ActivatedRoute,
private translateService: TranslateService,
+ @Optional() @Inject(APP_CONFIG) private appConfig?: AppConfig,
) {
}
ngOnInit() {
+ this.isBlank = this.isBlank ?? this.appConfig?.item?.bitstream?.openDownloadLinksInNewTab;
+
if (this.enableRequestACopy) {
// Obtain item request data from the route snapshot
this.itemRequest = this.route.snapshot.data.itemRequest;
diff --git a/src/config/default-app-config.ts b/src/config/default-app-config.ts
index fd703d4d024..1801bc2471b 100644
--- a/src/config/default-app-config.ts
+++ b/src/config/default-app-config.ts
@@ -412,6 +412,8 @@ export class DefaultAppConfig implements AppConfig {
pageSize: 5,
// Show the bitstream access status label
showAccessStatuses: false,
+ // Open bitstream download links in a new browser tab by default
+ openDownloadLinksInNewTab: false,
},
// Configuration for the metadata link view popover
metadataLinkViewPopoverData: {
diff --git a/src/config/item-config.interface.ts b/src/config/item-config.interface.ts
index 8c6792ff620..228df8d0395 100644
--- a/src/config/item-config.interface.ts
+++ b/src/config/item-config.interface.ts
@@ -18,6 +18,8 @@ export interface ItemConfig extends Config {
pageSize: number;
// Show the bitstream access status label
showAccessStatuses: boolean;
+ // Open bitstream download links in a new browser tab by default
+ openDownloadLinksInNewTab?: boolean;
}
metadataLinkViewPopoverData: MetadataLinkViewPopoverDataConfig