diff --git a/src/app/core/utilities/item-iiif-utils.ts b/src/app/core/utilities/item-iiif-utils.ts
index ec96fec3de2..6b684f0e07d 100644
--- a/src/app/core/utilities/item-iiif-utils.ts
+++ b/src/app/core/utilities/item-iiif-utils.ts
@@ -13,12 +13,12 @@ import { RouteService } from '../services/route.service';
import { Item } from '../shared/item.model';
export const isIiifEnabled = (item: Item) => {
- return !!item.firstMetadataValue('dspace.iiif.enabled');
+ return String(item.firstMetadataValue('dspace.iiif.enabled')?.valueOf?.() || '').trim().toLowerCase() === 'true';
};
export const isIiifSearchEnabled = (item: Item) => {
- return !!item.firstMetadataValue('iiif.search.enabled');
+ return String(item.firstMetadataValue('iiif.search.enabled')?.valueOf?.() || '').trim().toLowerCase() === 'true';
};
diff --git a/src/app/item-page/mirador-viewer/mirador-viewer.component.html b/src/app/item-page/mirador-viewer/mirador-viewer.component.html
index 7f2d0c0aac3..93e8d1cd1ef 100644
--- a/src/app/item-page/mirador-viewer/mirador-viewer.component.html
+++ b/src/app/item-page/mirador-viewer/mirador-viewer.component.html
@@ -1,8 +1,10 @@
-
{{'iiifviewer.fullscreen.notice' | translate}}
-@if (!isViewerAvailable) {
- {{viewerMessage}}
-}
-@if (isViewerAvailable) {
-
+@if (isIiifEnabled$ | async) {
+ {{'iiifviewer.fullscreen.notice' | translate}}
+ @if (!isViewerAvailable) {
+ {{viewerMessage}}
+ }
+ @if (isViewerAvailable) {
+
+ }
}
diff --git a/src/app/item-page/mirador-viewer/mirador-viewer.component.spec.ts b/src/app/item-page/mirador-viewer/mirador-viewer.component.spec.ts
index 39e515cc26f..a0bbd5942ab 100644
--- a/src/app/item-page/mirador-viewer/mirador-viewer.component.spec.ts
+++ b/src/app/item-page/mirador-viewer/mirador-viewer.component.spec.ts
@@ -4,8 +4,11 @@ import {
TestBed,
waitForAsync,
} from '@angular/core/testing';
+import { By } from '@angular/platform-browser';
import { BitstreamDataService } from '@dspace/core/data/bitstream-data.service';
import { BundleDataService } from '@dspace/core/data/bundle-data.service';
+import { ConfigurationDataService } from '@dspace/core/data/configuration-data.service';
+import { ConfigurationProperty } from '@dspace/core/shared/configuration-property.model';
import { Item } from '@dspace/core/shared/item.model';
import { MetadataMap } from '@dspace/core/shared/metadata.models';
import { TranslateLoaderMock } from '@dspace/core/testing/translate-loader.mock';
@@ -16,6 +19,11 @@ import {
TranslateModule,
} from '@ngx-translate/core';
import { of } from 'rxjs';
+import {
+ skip,
+ take,
+ toArray,
+} from 'rxjs/operators';
import { HostWindowService } from '../../shared/host-window.service';
import { createRelationshipsObservable } from '../simple/item-types/shared/item.component.spec';
@@ -23,14 +31,6 @@ import { MiradorViewerComponent } from './mirador-viewer.component';
import { MiradorViewerService } from './mirador-viewer.service';
-function getItem(metadata: MetadataMap) {
- return Object.assign(new Item(), {
- bundles: createSuccessfulRemoteDataObject$(createPaginatedList([])),
- metadata: metadata,
- relationships: createRelationshipsObservable(),
- });
-}
-
const noMetadata = new MetadataMap();
const mockHostWindowService = {
@@ -38,58 +38,100 @@ const mockHostWindowService = {
widthCategory: of(true),
};
-describe('MiradorViewerComponent with search', () => {
- let comp: MiradorViewerComponent;
- let fixture: ComponentFixture;
- const viewerService = jasmine.createSpyObj('MiradorViewerService', ['showEmbeddedViewer', 'getImageCount']);
+let comp: MiradorViewerComponent;
+let fixture: ComponentFixture;
+let configurationDataService: jasmine.SpyObj;
+let viewerService: jasmine.SpyObj;
- beforeEach(waitForAsync(() => {
- viewerService.showEmbeddedViewer.and.returnValue(true);
- TestBed.configureTestingModule({
- imports: [TranslateModule.forRoot({
+function getItem(metadata: MetadataMap) {
+ return Object.assign(new Item(), {
+ bundles: createSuccessfulRemoteDataObject$(createPaginatedList([])),
+ metadata: metadata,
+ relationships: createRelationshipsObservable(),
+ });
+}
+
+function setupTestBed(overrides?: {
+ showEmbedded?: boolean;
+ imageCount?: number;
+ iiifEnabled?: boolean;
+}) {
+ configurationDataService = jasmine.createSpyObj('ConfigurationDataService', [
+ 'findByPropertyName',
+ ]);
+
+ viewerService = jasmine.createSpyObj('MiradorViewerService', [
+ 'showEmbeddedViewer',
+ 'getImageCount',
+ 'isIiifEnabled',
+ ]);
+
+ viewerService.showEmbeddedViewer.and.returnValue(overrides?.showEmbedded ?? true);
+ viewerService.getImageCount.and.returnValue(of(overrides?.imageCount ?? 1));
+ viewerService.isIiifEnabled.and.returnValue(of(overrides?.iiifEnabled ?? true));
+
+ TestBed.configureTestingModule({
+ imports: [
+ TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderMock,
},
- }), MiradorViewerComponent],
- providers: [
- { provide: BitstreamDataService, useValue: {} },
- { provide: BundleDataService, useValue: {} },
- { provide: HostWindowService, useValue: mockHostWindowService },
- ],
- schemas: [NO_ERRORS_SCHEMA],
- }).overrideComponent(MiradorViewerComponent, {
- set: {
- providers: [
- { provide: MiradorViewerService, useValue: viewerService },
- ],
- },
- }).compileComponents();
+ }),
+ MiradorViewerComponent,
+ ],
+ providers: [
+ { provide: BitstreamDataService, useValue: {} },
+ { provide: BundleDataService, useValue: {} },
+ { provide: ConfigurationDataService, useValue: configurationDataService },
+ { provide: HostWindowService, useValue: mockHostWindowService },
+ { provide: MiradorViewerService, useValue: viewerService },
+ ],
+ schemas: [NO_ERRORS_SCHEMA],
+ });
+}
+
+function createComponent(options?: {
+ searchable?: boolean;
+ object?: any;
+}) {
+ fixture = TestBed.createComponent(MiradorViewerComponent);
+ comp = fixture.componentInstance;
+ comp.object = options?.object ?? getItem(noMetadata);
+ comp.searchable = options?.searchable ?? false;
+ fixture.detectChanges();
+}
+
+function getViewerSrc(): string {
+ return fixture.debugElement.query(By.css('#mirador-viewer'))
+ .nativeElement.src;
+}
+
+describe('MiradorViewerComponent with search', () => {
+ beforeEach(waitForAsync(() => {
+ setupTestBed();
+ TestBed.compileComponents();
}));
describe('searchable item', () => {
- beforeEach(waitForAsync(() => {
- fixture = TestBed.createComponent(MiradorViewerComponent);
- comp = fixture.componentInstance;
- comp.object = getItem(noMetadata);
- comp.searchable = true;
- fixture.detectChanges();
- }));
+ beforeEach(() => {
+ createComponent({ searchable: true });
+ });
it('should set multi property to true', (() => {
expect(comp.multi).toBe(true);
}));
- it('should set url "multi" param to true', (() => {
- const value = fixture.debugElement
- .nativeElement.querySelector('#mirador-viewer').src;
- expect(value).toContain('multi=true');
- }));
+ it('should set url "multi" param to true', async () => {
+ await fixture.whenStable();
+ fixture.detectChanges();
+ expect(getViewerSrc()).toContain('multi=true');
+ });
- it('should set url "searchable" param to true', (() => {
- const value = fixture.debugElement
- .nativeElement.querySelector('#mirador-viewer').src;
- expect(value).toContain('searchable=true');
- }));
+ it('should set url "searchable" param to true', async () => {
+ await fixture.whenStable();
+ fixture.detectChanges();
+ expect(getViewerSrc()).toContain('searchable=true');
+ });
it('should not call mirador service image count', () => {
expect(viewerService.getImageCount).not.toHaveBeenCalled();
@@ -99,108 +141,52 @@ describe('MiradorViewerComponent with search', () => {
});
describe('MiradorViewerComponent with multiple images', () => {
-
- let comp: MiradorViewerComponent;
- let fixture: ComponentFixture;
- const viewerService = jasmine.createSpyObj('MiradorViewerService', ['showEmbeddedViewer', 'getImageCount']);
-
beforeEach(waitForAsync(() => {
- viewerService.showEmbeddedViewer.and.returnValue(true);
- viewerService.getImageCount.and.returnValue(of(2));
- TestBed.configureTestingModule({
- imports: [TranslateModule.forRoot({
- loader: {
- provide: TranslateLoader,
- useClass: TranslateLoaderMock,
- },
- }), MiradorViewerComponent],
- providers: [
- { provide: BitstreamDataService, useValue: {} },
- { provide: BundleDataService, useValue: {} },
- { provide: HostWindowService, useValue: mockHostWindowService },
- ],
- schemas: [NO_ERRORS_SCHEMA],
- }).overrideComponent(MiradorViewerComponent, {
- set: {
- providers: [
- { provide: MiradorViewerService, useValue: viewerService },
- ],
- },
- }).compileComponents();
+ setupTestBed({ imageCount: 2 });
+ TestBed.compileComponents();
}));
describe('non-searchable item with multiple images', () => {
- beforeEach(waitForAsync(() => {
- fixture = TestBed.createComponent(MiradorViewerComponent);
- comp = fixture.componentInstance;
- comp.object = getItem(noMetadata);
- comp.searchable = false;
- fixture.detectChanges();
- }));
+ beforeEach(() => {
+ createComponent();
+ });
- it('should set url "multi" param to true', (() => {
- const value = fixture.debugElement
- .nativeElement.querySelector('#mirador-viewer').src;
- expect(value).toContain('multi=true');
- }));
+ it('should set url "multi" param to true', async () => {
+ await fixture.whenStable();
+ fixture.detectChanges();
+ expect(getViewerSrc()).toContain('multi=true');
+ });
it('should call mirador service image count', () => {
expect(viewerService.getImageCount).toHaveBeenCalled();
});
- it('should omit "searchable" param from url', (() => {
- const value = fixture.debugElement
- .nativeElement.querySelector('#mirador-viewer').src;
- expect(value).not.toContain('searchable=true');
- }));
+ it('should omit "searchable" param from url', async () => {
+ await fixture.whenStable();
+ fixture.detectChanges();
+ expect(getViewerSrc()).not.toContain('searchable=true');
+ });
});
});
describe('MiradorViewerComponent with a single image', () => {
- let comp: MiradorViewerComponent;
- let fixture: ComponentFixture;
- const viewerService = jasmine.createSpyObj('MiradorViewerService', ['showEmbeddedViewer', 'getImageCount']);
-
beforeEach(waitForAsync(() => {
- viewerService.showEmbeddedViewer.and.returnValue(true);
- viewerService.getImageCount.and.returnValue(of(1));
- TestBed.configureTestingModule({
- imports: [TranslateModule.forRoot({
- loader: {
- provide: TranslateLoader,
- useClass: TranslateLoaderMock,
- },
- }), MiradorViewerComponent],
- providers: [
- { provide: BitstreamDataService, useValue: {} },
- { provide: BundleDataService, useValue: {} },
- { provide: HostWindowService, useValue: mockHostWindowService },
- ],
- schemas: [NO_ERRORS_SCHEMA],
- }).overrideComponent(MiradorViewerComponent, {
- set: {
- providers: [
- { provide: MiradorViewerService, useValue: viewerService },
- ],
- },
- }).compileComponents();
+ setupTestBed({ imageCount: 1 });
+ TestBed.compileComponents();
}));
describe('single image viewer', () => {
- beforeEach(waitForAsync(() => {
- fixture = TestBed.createComponent(MiradorViewerComponent);
- comp = fixture.componentInstance;
- comp.object = getItem(noMetadata);
- fixture.detectChanges();
- }));
+ beforeEach(() => {
+ createComponent();
+ });
- it('should omit "multi" param', (() => {
- const value = fixture.debugElement
- .nativeElement.querySelector('#mirador-viewer').src;
- expect(value).not.toContain('multi=false');
- }));
+ it('should omit "multi" param', async () => {
+ await fixture.whenStable();
+ fixture.detectChanges();
+ expect(getViewerSrc()).not.toContain('multi=false');
+ });
it('should call mirador service image count', () => {
expect(viewerService.getImageCount).toHaveBeenCalled();
@@ -211,54 +197,99 @@ describe('MiradorViewerComponent with a single image', () => {
});
describe('MiradorViewerComponent in development mode', () => {
- let comp: MiradorViewerComponent;
- let fixture: ComponentFixture;
- const viewerService = jasmine.createSpyObj('MiradorViewerService', ['showEmbeddedViewer', 'getImageCount']);
-
beforeEach(waitForAsync(() => {
- viewerService.showEmbeddedViewer.and.returnValue(false);
- viewerService.getImageCount.and.returnValue(of(1));
- TestBed.configureTestingModule({
- imports: [TranslateModule.forRoot({
- loader: {
- provide: TranslateLoader,
- useClass: TranslateLoaderMock,
- },
- }), MiradorViewerComponent],
- providers: [
- { provide: BitstreamDataService, useValue: {} },
- ],
- schemas: [NO_ERRORS_SCHEMA],
- }).overrideComponent(MiradorViewerComponent, {
- set: {
- providers: [
- { provide: MiradorViewerService, useValue: viewerService },
- { provide: BundleDataService, useValue: {} },
- { provide: HostWindowService, useValue: mockHostWindowService },
- ],
- },
- }).compileComponents();
+ setupTestBed({
+ showEmbedded: false,
+ imageCount: 1,
+ });
+ TestBed.compileComponents();
}));
describe('embedded viewer', () => {
- beforeEach(waitForAsync(() => {
- fixture = TestBed.createComponent(MiradorViewerComponent);
- comp = fixture.componentInstance;
- comp.object = getItem(noMetadata);
- fixture.detectChanges();
- }));
+ beforeEach(() => {
+ createComponent();
+ });
- it('should not embed the viewer', (() => {
+ it('should not embed the viewer', async () => {
+ await fixture.whenStable();
+ fixture.detectChanges();
const value = fixture.debugElement
.nativeElement.querySelector('#mirador-viewer');
expect(value).toBeNull();
- }));
+ });
- it('should show message', (() => {
+ it('should show message', async () => {
+ await fixture.whenStable();
+ fixture.detectChanges();
const value = fixture.debugElement
.nativeElement.querySelector('#viewer-message');
expect(value).not.toBeNull();
- }));
+ });
});
});
+
+
+describe('MiradorViewerService whether IIIF is enabled in the repository', () => {
+ let miradorViewerService: MiradorViewerService;
+ function mockIiifEnabled(values: string[]): void {
+ configurationDataService.findByPropertyName.and.returnValue(
+ createSuccessfulRemoteDataObject$(
+ Object.assign(new ConfigurationProperty(), {
+ name: 'iiif.enabled',
+ values,
+ }),
+ ),
+ );
+ }
+ beforeEach(() => {
+ configurationDataService = jasmine.createSpyObj('ConfigurationDataService', [
+ 'findByPropertyName',
+ ]);
+ miradorViewerService = new MiradorViewerService();
+ });
+ describe('isIiifEnabled', () => {
+ it('should return false initially and then true', (done) => {
+ mockIiifEnabled(['true']);
+ miradorViewerService.isIiifEnabled(configurationDataService)
+ .pipe(take(2), toArray())
+ .subscribe((results) => {
+ expect(results).toEqual([false, true]);
+ done();
+ });
+ });
+
+ it('should return true when iiif.enabled is true', (done) => {
+ mockIiifEnabled(['true']);
+
+ miradorViewerService.isIiifEnabled(configurationDataService)
+ .pipe(skip(1))
+ .subscribe((enabled) => {
+ expect(enabled).toBeTrue();
+ expect(configurationDataService.findByPropertyName)
+ .toHaveBeenCalledWith('iiif.enabled');
+ done();
+ });
+ });
+
+ it('should return false when iiif.enabled is false', (done) => {
+ mockIiifEnabled(['false']);
+ miradorViewerService.isIiifEnabled(configurationDataService)
+ .pipe(skip(1))
+ .subscribe((enabled) => {
+ expect(enabled).toBeFalse();
+ done();
+ });
+ });
+
+ it('should return false when configuration value is missing', (done) => {
+ mockIiifEnabled([]);
+ miradorViewerService.isIiifEnabled(configurationDataService)
+ .pipe(skip(1))
+ .subscribe((enabled) => {
+ expect(enabled).toBeFalse();
+ done();
+ });
+ });
+ });
+});
diff --git a/src/app/item-page/mirador-viewer/mirador-viewer.component.ts b/src/app/item-page/mirador-viewer/mirador-viewer.component.ts
index 04ff4a9fa88..7700d304482 100644
--- a/src/app/item-page/mirador-viewer/mirador-viewer.component.ts
+++ b/src/app/item-page/mirador-viewer/mirador-viewer.component.ts
@@ -16,6 +16,7 @@ import {
} from '@angular/platform-browser';
import { BitstreamDataService } from '@dspace/core/data/bitstream-data.service';
import { BundleDataService } from '@dspace/core/data/bundle-data.service';
+import { ConfigurationDataService } from '@dspace/core/data/configuration-data.service';
import { WidthCategory } from '@dspace/core/shared/host-window-type';
import { Item } from '@dspace/core/shared/item.model';
import { TranslateModule } from '@ngx-translate/core';
@@ -61,6 +62,11 @@ export class MiradorViewerComponent implements OnInit {
*/
isViewerAvailable = true;
+ /**
+ * Check if IIIF is enabled in the repository.
+ */
+ isIiifEnabled$: Observable;
+
/**
* The url for the iframe.
*/
@@ -83,6 +89,7 @@ export class MiradorViewerComponent implements OnInit {
private bitstreamDataService: BitstreamDataService,
private bundleDataService: BundleDataService,
private hostWindowService: HostWindowService,
+ private configurationDataService: ConfigurationDataService,
@Inject(PLATFORM_ID) private platformId: any) {
}
@@ -163,5 +170,7 @@ export class MiradorViewerComponent implements OnInit {
);
}
}
+ // Set the property whether IIIF is enabled in the repository
+ this.isIiifEnabled$ = this.viewerService.isIiifEnabled(this.configurationDataService);
}
}
diff --git a/src/app/item-page/mirador-viewer/mirador-viewer.service.ts b/src/app/item-page/mirador-viewer/mirador-viewer.service.ts
index 0af0f3218e3..9d54c7432c1 100644
--- a/src/app/item-page/mirador-viewer/mirador-viewer.service.ts
+++ b/src/app/item-page/mirador-viewer/mirador-viewer.service.ts
@@ -4,6 +4,7 @@ import {
} from '@angular/core';
import { BitstreamDataService } from '@dspace/core/data/bitstream-data.service';
import { BundleDataService } from '@dspace/core/data/bundle-data.service';
+import { ConfigurationDataService } from '@dspace/core/data/configuration-data.service';
import { PaginatedList } from '@dspace/core/data/paginated-list.model';
import { RemoteData } from '@dspace/core/data/remote-data';
import { Bitstream } from '@dspace/core/shared/bitstream.model';
@@ -14,13 +15,17 @@ import {
FollowLinkConfig,
} from '@dspace/core/shared/follow-link-config.model';
import { Item } from '@dspace/core/shared/item.model';
-import { getFirstCompletedRemoteData } from '@dspace/core/shared/operators';
+import {
+ getFirstCompletedRemoteData,
+ getFirstSucceededRemoteDataPayload,
+} from '@dspace/core/shared/operators';
import { Observable } from 'rxjs';
import {
filter,
last,
map,
mergeMap,
+ startWith,
switchMap,
} from 'rxjs/operators';
@@ -39,6 +44,22 @@ export class MiradorViewerService {
return !isDevMode();
}
+ /**
+ * Returns observable of boolean whether IIIF is enabled in the repository.
+ * The default value is false.
+ * @param configurationDataService
+ * @returns the configuration value of iiif.enabled
+ */
+ isIiifEnabled (configurationDataService: ConfigurationDataService): Observable {
+ return configurationDataService.findByPropertyName('iiif.enabled')
+ .pipe(getFirstSucceededRemoteDataPayload(),
+ map((configurationProperty) =>
+ configurationProperty.values?.[0] === 'true',
+ ),
+ startWith(false),
+ );
+ }
+
/**
* Returns observable of the number of images found in eligible IIIF bundles. Checks
* the mimetype of the first 5 bitstreams in each bundle.