Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Angular support for IIIF and Mirador #1079

Merged
merged 67 commits into from
Oct 22, 2021
Merged
Show file tree
Hide file tree
Changes from 65 commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
156e9a0
Added mirador deps and scripts to package.json
mspalti Mar 27, 2021
a56ebad
Added webpack configuration for mirador.
mspalti Mar 27, 2021
7e1c441
Added mirador route to express server.
mspalti Mar 27, 2021
c6bc21f
Added iiif entity group.
mspalti Mar 27, 2021
27afd41
Added FileSectionComponent to shared module.
mspalti Mar 27, 2021
6081dab
Added mirador files for webpack build
mspalti Mar 27, 2021
30ff10e
Added iiif entity module to parent item module.
mspalti Mar 27, 2021
2ec1096
Added iiif labels to en.json5
mspalti Mar 27, 2021
f377347
Updates to iiif list elements.
mspalti Mar 27, 2021
aa27dda
yarn.lock
mspalti Mar 27, 2021
3b5df5d
Added mirador deps and scripts to package.json
mspalti Mar 27, 2021
c02983c
Added webpack configuration for mirador.
mspalti Mar 27, 2021
42802bd
Added mirador route to express server.
mspalti Mar 27, 2021
23e7675
Added iiif entity group.
mspalti Mar 27, 2021
71851fe
Added FileSectionComponent to shared module.
mspalti Mar 27, 2021
2d694a8
Added mirador files for webpack build
mspalti Mar 27, 2021
187ae50
Added iiif entity module to parent item module.
mspalti Mar 27, 2021
45c6f4e
Added iiif labels to en.json5
mspalti Mar 27, 2021
5a8f38a
Updates to iiif list elements.
mspalti Mar 27, 2021
0330b3e
yarn.lock
mspalti Mar 27, 2021
f52ed2a
Updated iiif component tests.
mspalti Mar 30, 2021
c0aac8a
Added mobile breakpoint for mirador viewer configuration.
mspalti Mar 30, 2021
e4a51af
Merge branch 'iiif-mirador' of https://github.com/mspalti/dspace-angu…
mspalti Mar 30, 2021
0250b18
Changed property name
mspalti Mar 30, 2021
97e8c9b
Added title to the mirador iframe.
mspalti Mar 30, 2021
3744abb
Allow canvas side panel on all views.
mspalti Apr 1, 2021
ce11ae2
Merge branch 'main' into iiif-mirador
mspalti Apr 1, 2021
3bc7739
Minor fix in module.
mspalti Apr 1, 2021
247ae73
Merge branch 'main' into iiif-mirador
mspalti Apr 2, 2021
6f55225
Removed unused variable.
mspalti Apr 2, 2021
c37b315
Merge remote-tracking branch 'upstream/main' into iiif-mirador
mspalti Apr 2, 2021
2561d54
Added comments
mspalti Apr 16, 2021
4791cce
Merge branch 'main' into iiif-mirador
mspalti Apr 16, 2021
98571a4
Merge remote-tracking branch 'origin/iiif-mirador' into iiif-mirador
mspalti Apr 20, 2021
3dacbe5
Merge branch 'main' into iiif-mirador
mspalti May 16, 2021
3bd8e35
Added description field to iiif item view.
mspalti May 18, 2021
da2bbce
Merge branch 'main' into iiif-mirador
mspalti May 18, 2021
9c41cd7
Merge branch 'main' into iiif-mirador
mspalti Jul 11, 2021
de352a8
Retrieve thumbnail from remote data object.
mspalti Jul 12, 2021
20477f0
Merge branch 'main' into iiif-mirador
mspalti Jul 30, 2021
9cc3351
Fixed item page component paths.
mspalti Jul 30, 2021
6019a21
Removed unused import.
mspalti Jul 31, 2021
fb0d51c
Improved performance of mirador component by avoiding IIIF bundle bit…
mspalti Aug 19, 2021
668a08b
Updated the iiif endpoint that is passed to the viewer.
mspalti Aug 25, 2021
ded5e29
Merge branch 'main' into iiif-mirador
mspalti Sep 17, 2021
3bf9c5f
Starting update for iiif using non-entity metadata.
mspalti Sep 28, 2021
abb733b
Merge branch 'main' into iiif-mirador
mspalti Sep 28, 2021
ec0e8c7
Completed the initial embed of mirador viewer.
mspalti Sep 28, 2021
670a0b8
Completed work on angular tests.
mspalti Sep 29, 2021
d4a6ed6
Mirador component multi-view based on count of image files in the def…
mspalti Sep 30, 2021
baa94ca
Fixed proble with mirador iframe url for a single image.
mspalti Oct 8, 2021
681b10e
Removed unused import.
mspalti Oct 8, 2021
2d11136
Viewer updates.
mspalti Oct 12, 2021
538e3cb
Mirador component update.
mspalti Oct 12, 2021
a875f68
Merge branch 'iiif-mirador' of https://github.com/mspalti/dspace-angu…
mspalti Oct 12, 2021
b738065
Updated service mock for tests.
mspalti Oct 14, 2021
8c05c6d
Merge branch 'main' into iiif-mirador
mspalti Oct 14, 2021
3a1abe8
Removed unused import.
mspalti Oct 14, 2021
24a6a4c
Checking for dev mode to prevent viewer embed.
mspalti Oct 14, 2021
80a9770
More neutral primary color in mirador viewer configuration.
mspalti Oct 14, 2021
073296e
Mirador component update and spec.
mspalti Oct 16, 2021
6a2d856
Removed unused import.
mspalti Oct 16, 2021
a3511ab
Merge branch 'iiif-mirador' of https://github.com/mspalti/dspace-angu…
mspalti Oct 18, 2021
8ac122b
Updated viewport size check.
mspalti Oct 18, 2021
b0fcdf6
Updated test.
mspalti Oct 18, 2021
2b19b16
Merge branch 'main' into iiif-mirador
mspalti Oct 20, 2021
2c60cc4
Updated versioned-item to provide route service in super constructor …
mspalti Oct 20, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"serve": "ts-node --project ./tsconfig.ts-node.json scripts/serve.ts",
"start:dev": "npm-run-all --parallel config:dev:watch serve",
"start:prod": "yarn run build:prod && yarn run serve:ssr",
"start:mirador:prod": "yarn run build:mirador && yarn run start:prod",
"analyze": "webpack-bundle-analyzer dist/browser/stats.json",
"build": "ng build",
"build:stats": "ng build --stats-json",
Expand All @@ -44,6 +45,7 @@
"clean": "yarn run clean:prod && yarn run clean:env && yarn run clean:node",
"clean:env": "rimraf src/environments/environment.ts",
"sync-i18n": "yarn run config:dev && ts-node --project ./tsconfig.ts-node.json scripts/sync-i18n-files.ts",
"build:mirador": "webpack --config webpack/webpack.mirador.config.ts",
"merge-i18n": "yarn run config:dev && ts-node --project ./tsconfig.ts-node.json scripts/merge-i18n-files.ts",
"postinstall": "ngcc",
"cypress:open": "cypress open",
Expand Down Expand Up @@ -106,6 +108,9 @@
"jsonschema": "1.4.0",
"jwt-decode": "^3.1.2",
"klaro": "^0.7.10",
"mirador": "^3.0.0",
"mirador-dl-plugin": "^0.13.0",
"mirador-share-plugin": "^0.10.0",
"moment": "^2.29.1",
"morgan": "^1.10.0",
"ng-mocks": "10.5.4",
Expand All @@ -118,6 +123,8 @@
"nouislider": "^14.6.3",
"pem": "1.14.4",
"postcss-cli": "^8.3.0",
"react": "^16.14.0",
"react-dom": "^16.14.0",
"reflect-metadata": "^0.1.13",
"rxjs": "^6.6.3",
"rxjs-spy": "^7.5.3",
Expand Down Expand Up @@ -157,6 +164,7 @@
"deep-freeze": "0.0.1",
"dotenv": "^8.2.0",
"fork-ts-checker-webpack-plugin": "^6.0.3",
"html-loader": "^1.3.2",
"html-webpack-plugin": "^4.5.0",
"http-proxy-middleware": "^1.0.5",
"jasmine-core": "^3.6.0",
Expand Down
6 changes: 6 additions & 0 deletions server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ import { UIServerConfig } from './src/config/ui-server-config.interface';
* Set path for the browser application's dist folder
*/
const DIST_FOLDER = join(process.cwd(), 'dist/browser');
// Set path fir IIIF viewer.
const IIIF_VIEWER = join(process.cwd(), 'dist/iiif');

const indexHtml = existsSync(join(DIST_FOLDER, 'index.html')) ? 'index.html' : 'index';

Expand Down Expand Up @@ -135,6 +137,10 @@ export function app() {
* Serve static resources (images, i18n messages, …)
*/
server.get('*.*', cacheControl, express.static(DIST_FOLDER, { index: false }));
/*
* Fallthrough to the IIIF viewer (must be included in the build).
*/
server.use('/iiif', express.static(IIIF_VIEWER, {index:false}));

// Register the ngApp callback function to handle incoming requests
server.get('*', ngApp);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-dat
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
import { JournalComponent } from './journal.component';
import { RouteService } from '../../../../core/services/route.service';

let comp: JournalComponent;
let fixture: ComponentFixture<JournalComponent>;
Expand Down Expand Up @@ -86,6 +87,7 @@ describe('JournalComponent', () => {
{ provide: NotificationsService, useValue: {} },
{ provide: DefaultChangeAnalyzer, useValue: {} },
{ provide: BitstreamDataService, useValue: mockBitstreamDataService },
{ provide: RouteService, useValue: {} }
],

schemas: [NO_ERRORS_SCHEMA]
Expand Down
9 changes: 5 additions & 4 deletions src/app/item-page/item-page.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { ItemPageAbstractFieldComponent } from './simple/field-components/specif
import { ItemPageUriFieldComponent } from './simple/field-components/specific-field/uri/item-page-uri-field.component';
import { ItemPageTitleFieldComponent } from './simple/field-components/specific-field/title/item-page-title-field.component';
import { ItemPageFieldComponent } from './simple/field-components/specific-field/item-page-field.component';
import { FileSectionComponent } from './simple/field-components/file-section/file-section.component';
import { CollectionsComponent } from './field-components/collections/collections.component';
import { FullItemPageComponent } from './full/full-item-page.component';
import { FullFileSectionComponent } from './full/field-components/file-section/full-file-section.component';
Expand All @@ -31,8 +30,10 @@ import { MediaViewerComponent } from './media-viewer/media-viewer.component';
import { MediaViewerVideoComponent } from './media-viewer/media-viewer-video/media-viewer-video.component';
import { MediaViewerImageComponent } from './media-viewer/media-viewer-image/media-viewer-image.component';
import { NgxGalleryModule } from '@kolkov/ngx-gallery';
import { MiradorViewerComponent } from './mirador-viewer/mirador-viewer.component';
import { ThemedFileSectionComponent} from './simple/field-components/file-section/themed-file-section.component';


const ENTRY_COMPONENTS = [
// put only entry components that use custom decorator
PublicationComponent,
Expand All @@ -52,7 +53,6 @@ const DECLARATIONS = [
ItemPageUriFieldComponent,
ItemPageTitleFieldComponent,
ItemPageFieldComponent,
FileSectionComponent,
CollectionsComponent,
FullFileSectionComponent,
PublicationComponent,
Expand All @@ -62,7 +62,8 @@ const DECLARATIONS = [
AbstractIncrementalListComponent,
MediaViewerComponent,
MediaViewerVideoComponent,
MediaViewerImageComponent
MediaViewerImageComponent,
MiradorViewerComponent
];

@NgModule({
Expand All @@ -74,7 +75,7 @@ const DECLARATIONS = [
StatisticsModule.forRoot(),
JournalEntitiesModule.withEntryComponents(),
ResearchEntitiesModule.withEntryComponents(),
NgxGalleryModule,
NgxGalleryModule,
],
declarations: [
...DECLARATIONS
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<p class="full-text-op">{{'iiifviewer.fullscreen.notice' | translate}}</p>
<p *ngIf="!isViewerAvailable" id="viewer-message">{{viewerMessage}}</p>
<iframe title="Mirador Viewer" allowtransparency="true" *ngIf="isViewerAvailable" [src]="iframeViewerUrl | async" id="mirador-viewer"></iframe>

13 changes: 13 additions & 0 deletions src/app/item-page/mirador-viewer/mirador-viewer.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#mirador-viewer {
border: 1px solid #dee2e6;
height: 660px;
width: 100%
}
.full-text-op {
text-align: right;
color: #333333;
font-size: 0.8em;
}
p.full-text-op {
margin-bottom: 0;
}
255 changes: 255 additions & 0 deletions src/app/item-page/mirador-viewer/mirador-viewer.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { MiradorViewerComponent } from './mirador-viewer.component';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateLoaderMock } from '../../shared/mocks/translate-loader.mock';
import { BitstreamDataService } from '../../core/data/bitstream-data.service';
import { createRelationshipsObservable } from '../simple/item-types/shared/item.component.spec';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { MetadataMap } from '../../core/shared/metadata.models';
import { Item } from '../../core/shared/item.model';
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
import { createPaginatedList } from '../../shared/testing/utils.test';
import { of as observableOf } from 'rxjs';
import { MiradorViewerService } from './mirador-viewer.service';
import { HostWindowService } from '../../shared/host-window.service';


function getItem(metadata: MetadataMap) {
return Object.assign(new Item(), {
bundles: createSuccessfulRemoteDataObject$(createPaginatedList([])),
metadata: metadata,
relationships: createRelationshipsObservable()
});
}

const noMetadata = new MetadataMap();

const mockHostWindowService = {
// This isn't really testing mobile status, the return observable just allows the test to run.
widthCategory: observableOf(true),
};

describe('MiradorViewerComponent with search', () => {
let comp: MiradorViewerComponent;
let fixture: ComponentFixture<MiradorViewerComponent>;
const viewerService = jasmine.createSpyObj('MiradorViewerService', ['showEmbeddedViewer', 'getImageCount']);

beforeEach(waitForAsync(() => {
viewerService.showEmbeddedViewer.and.returnValue(true);
TestBed.configureTestingModule({
imports: [TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderMock
}
})],
declarations: [MiradorViewerComponent],
providers: [
{ provide: BitstreamDataService, useValue: {} },
{ provide: HostWindowService, useValue: mockHostWindowService }
],
schemas: [NO_ERRORS_SCHEMA]
}).overrideComponent(MiradorViewerComponent, {
set: {
providers: [
{ provide: MiradorViewerService, useValue: viewerService }
]
}
}).compileComponents();
}));
describe('searchable item', () => {
beforeEach(waitForAsync(() => {
fixture = TestBed.createComponent(MiradorViewerComponent);
comp = fixture.componentInstance;
comp.object = getItem(noMetadata);
comp.searchable = true;
fixture.detectChanges();
}));

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 "searchable" param to true', (() => {
const value = fixture.debugElement
.nativeElement.querySelector('#mirador-viewer').src;
expect(value).toContain('searchable=true');
}));

it('should not call mirador service image count', () => {
expect(viewerService.getImageCount).not.toHaveBeenCalled();
});

});
});

describe('MiradorViewerComponent with multiple images', () => {

let comp: MiradorViewerComponent;
let fixture: ComponentFixture<MiradorViewerComponent>;
const viewerService = jasmine.createSpyObj('MiradorViewerService', ['showEmbeddedViewer', 'getImageCount']);

beforeEach(waitForAsync(() => {
viewerService.showEmbeddedViewer.and.returnValue(true);
viewerService.getImageCount.and.returnValue(observableOf(2));
TestBed.configureTestingModule({
imports: [TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderMock
}
})],
declarations: [MiradorViewerComponent],
providers: [
{ provide: BitstreamDataService, useValue: {} },
{ provide: HostWindowService, useValue: mockHostWindowService }
],
schemas: [NO_ERRORS_SCHEMA]
}).overrideComponent(MiradorViewerComponent, {
set: {
providers: [
{ provide: MiradorViewerService, useValue: viewerService }
]
}
}).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();
}));

it('should set url "multi" param to true', (() => {
const value = fixture.debugElement
.nativeElement.querySelector('#mirador-viewer').src;
expect(value).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');
}));

});
});


describe('MiradorViewerComponent with a single image', () => {
let comp: MiradorViewerComponent;
let fixture: ComponentFixture<MiradorViewerComponent>;
const viewerService = jasmine.createSpyObj('MiradorViewerService', ['showEmbeddedViewer', 'getImageCount']);

beforeEach(waitForAsync(() => {
viewerService.showEmbeddedViewer.and.returnValue(true);
viewerService.getImageCount.and.returnValue(observableOf(1));
TestBed.configureTestingModule({
imports: [TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderMock
}
})],
declarations: [MiradorViewerComponent],
providers: [
{ provide: BitstreamDataService, useValue: {} },
{ provide: HostWindowService, useValue: mockHostWindowService }
],
schemas: [NO_ERRORS_SCHEMA]
}).overrideComponent(MiradorViewerComponent, {
set: {
providers: [
{ provide: MiradorViewerService, useValue: viewerService }
]
}
}).compileComponents();
}));

describe('single image viewer', () => {
beforeEach(waitForAsync(() => {
fixture = TestBed.createComponent(MiradorViewerComponent);
comp = fixture.componentInstance;
comp.object = getItem(noMetadata);
fixture.detectChanges();
}));

it('should omit "multi" param', (() => {
const value = fixture.debugElement
.nativeElement.querySelector('#mirador-viewer').src;
expect(value).not.toContain('multi=false');
}));

it('should call mirador service image count', () => {
expect(viewerService.getImageCount).toHaveBeenCalled();
});

});

});

describe('MiradorViewerComponent in development mode', () => {
let comp: MiradorViewerComponent;
let fixture: ComponentFixture<MiradorViewerComponent>;
const viewerService = jasmine.createSpyObj('MiradorViewerService', ['showEmbeddedViewer', 'getImageCount']);

beforeEach(waitForAsync(() => {
viewerService.showEmbeddedViewer.and.returnValue(false);
viewerService.getImageCount.and.returnValue(observableOf(1));
TestBed.configureTestingModule({
imports: [TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderMock
}
})],
declarations: [MiradorViewerComponent],
providers: [
{ provide: BitstreamDataService, useValue: {} }
],
schemas: [NO_ERRORS_SCHEMA]
}).overrideComponent(MiradorViewerComponent, {
set: {
providers: [
{ provide: MiradorViewerService, useValue: viewerService },
{ provide: HostWindowService, useValue: mockHostWindowService }
]
}
}).compileComponents();
}));

describe('embedded viewer', () => {
beforeEach(waitForAsync(() => {
fixture = TestBed.createComponent(MiradorViewerComponent);
comp = fixture.componentInstance;
comp.object = getItem(noMetadata);
fixture.detectChanges();
}));

it('should not embed the viewer', (() => {
const value = fixture.debugElement
.nativeElement.querySelector('#mirador-viewer');
expect(value).toBeNull();
}));

it('should show message', (() => {
const value = fixture.debugElement
.nativeElement.querySelector('#viewer-message');
expect(value).toBeDefined();
}));

});
});
Loading