mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
Merge pull request #1438 from mspalti/iiif-bitstream-edit
Edit IIIF bitstream metadata
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ds-form [formId]="'edit-bitstream-form-id'"
|
||||
<ds-form *ngIf="formGroup" [formId]="'edit-bitstream-form-id'"
|
||||
[formGroup]="formGroup"
|
||||
[formModel]="formModel"
|
||||
[formLayout]="formLayout"
|
||||
|
@@ -6,3 +6,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
:host ::ng-deep ds-dynamic-form-control-container > div > label {
|
||||
margin-top: 1.75rem;
|
||||
}
|
||||
|
||||
|
@@ -22,6 +22,8 @@ import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } f
|
||||
import { getEntityEditRoute } from '../../item-page/item-page-routing-paths';
|
||||
import { createPaginatedList } from '../../shared/testing/utils.test';
|
||||
import { Item } from '../../core/shared/item.model';
|
||||
import { MetadataValueFilter } from '../../core/shared/metadata.models';
|
||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||
|
||||
const infoNotification: INotification = new Notification('id', NotificationType.Info, 'info');
|
||||
const warningNotification: INotification = new Notification('id', NotificationType.Warning, 'warning');
|
||||
@@ -31,22 +33,25 @@ let notificationsService: NotificationsService;
|
||||
let formService: DynamicFormService;
|
||||
let bitstreamService: BitstreamDataService;
|
||||
let bitstreamFormatService: BitstreamFormatDataService;
|
||||
let dsoNameService: DSONameService;
|
||||
let bitstream: Bitstream;
|
||||
let selectedFormat: BitstreamFormat;
|
||||
let allFormats: BitstreamFormat[];
|
||||
let router: Router;
|
||||
|
||||
describe('EditBitstreamPageComponent', () => {
|
||||
let comp: EditBitstreamPageComponent;
|
||||
let fixture: ComponentFixture<EditBitstreamPageComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
describe('EditBitstreamPageComponent', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
allFormats = [
|
||||
Object.assign({
|
||||
id: '1',
|
||||
shortDescription: 'Unknown',
|
||||
description: 'Unknown format',
|
||||
supportLevel: BitstreamFormatSupportLevel.Unknown,
|
||||
mimetype: 'application/octet-stream',
|
||||
_links: {
|
||||
self: {href: 'format-selflink-1'}
|
||||
}
|
||||
@@ -56,6 +61,7 @@ describe('EditBitstreamPageComponent', () => {
|
||||
shortDescription: 'PNG',
|
||||
description: 'Portable Network Graphics',
|
||||
supportLevel: BitstreamFormatSupportLevel.Known,
|
||||
mimetype: 'image/png',
|
||||
_links: {
|
||||
self: {href: 'format-selflink-2'}
|
||||
}
|
||||
@@ -65,19 +71,14 @@ describe('EditBitstreamPageComponent', () => {
|
||||
shortDescription: 'GIF',
|
||||
description: 'Graphics Interchange Format',
|
||||
supportLevel: BitstreamFormatSupportLevel.Known,
|
||||
mimetype: 'image/gif',
|
||||
_links: {
|
||||
self: {href: 'format-selflink-3'}
|
||||
}
|
||||
})
|
||||
] as BitstreamFormat[];
|
||||
selectedFormat = allFormats[1];
|
||||
notificationsService = jasmine.createSpyObj('notificationsService',
|
||||
{
|
||||
info: infoNotification,
|
||||
warning: warningNotification,
|
||||
success: successNotification
|
||||
}
|
||||
);
|
||||
|
||||
formService = Object.assign({
|
||||
createFormGroup: (fModel: DynamicFormControlModel[]) => {
|
||||
const controls = {};
|
||||
@@ -90,6 +91,26 @@ describe('EditBitstreamPageComponent', () => {
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
|
||||
bitstreamFormatService = jasmine.createSpyObj('bitstreamFormatService', {
|
||||
findAll: createSuccessfulRemoteDataObject$(createPaginatedList(allFormats))
|
||||
});
|
||||
|
||||
notificationsService = jasmine.createSpyObj('notificationsService',
|
||||
{
|
||||
info: infoNotification,
|
||||
warning: warningNotification,
|
||||
success: successNotification
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('EditBitstreamPageComponent no IIIF fields', () => {
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
|
||||
const bundleName = 'ORIGINAL';
|
||||
|
||||
bitstream = Object.assign(new Bitstream(), {
|
||||
metadata: {
|
||||
'dc.description': [
|
||||
@@ -109,7 +130,10 @@ describe('EditBitstreamPageComponent', () => {
|
||||
},
|
||||
bundle: createSuccessfulRemoteDataObject$({
|
||||
item: createSuccessfulRemoteDataObject$(Object.assign(new Item(), {
|
||||
uuid: 'some-uuid'
|
||||
uuid: 'some-uuid',
|
||||
firstMetadataValue(keyOrKeys: string | string[], valueFilter?: MetadataValueFilter): string {
|
||||
return undefined;
|
||||
},
|
||||
}))
|
||||
})
|
||||
});
|
||||
@@ -123,6 +147,9 @@ describe('EditBitstreamPageComponent', () => {
|
||||
bitstreamFormatService = jasmine.createSpyObj('bitstreamFormatService', {
|
||||
findAll: createSuccessfulRemoteDataObject$(createPaginatedList(allFormats))
|
||||
});
|
||||
dsoNameService = jasmine.createSpyObj('dsoNameService', {
|
||||
getName: bundleName
|
||||
});
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [TranslateModule.forRoot(), RouterTestingModule],
|
||||
@@ -130,8 +157,14 @@ describe('EditBitstreamPageComponent', () => {
|
||||
providers: [
|
||||
{provide: NotificationsService, useValue: notificationsService},
|
||||
{provide: DynamicFormService, useValue: formService},
|
||||
{ provide: ActivatedRoute, useValue: { data: observableOf({ bitstream: createSuccessfulRemoteDataObject(bitstream) }), snapshot: { queryParams: {} } } },
|
||||
{provide: ActivatedRoute,
|
||||
useValue: {
|
||||
data: observableOf({bitstream: createSuccessfulRemoteDataObject(bitstream)}),
|
||||
snapshot: {queryParams: {}}
|
||||
}
|
||||
},
|
||||
{provide: BitstreamDataService, useValue: bitstreamService},
|
||||
{provide: DSONameService, useValue: dsoNameService},
|
||||
{provide: BitstreamFormatDataService, useValue: bitstreamFormatService},
|
||||
ChangeDetectorRef
|
||||
],
|
||||
@@ -243,3 +276,233 @@ describe('EditBitstreamPageComponent', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('EditBitstreamPageComponent with IIIF fields', () => {
|
||||
|
||||
const bundleName = 'ORIGINAL';
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
|
||||
bitstream = Object.assign(new Bitstream(), {
|
||||
metadata: {
|
||||
'dc.description': [
|
||||
{
|
||||
value: 'Bitstream description'
|
||||
}
|
||||
],
|
||||
'dc.title': [
|
||||
{
|
||||
value: 'Bitstream title'
|
||||
}
|
||||
],
|
||||
'iiif.label': [
|
||||
{
|
||||
value: 'chapter one'
|
||||
}
|
||||
],
|
||||
'iiif.toc': [
|
||||
{
|
||||
value: 'chapter one'
|
||||
}
|
||||
],
|
||||
'iiif.image.width': [
|
||||
{
|
||||
value: '2400'
|
||||
}
|
||||
],
|
||||
'iiif.image.height': [
|
||||
{
|
||||
value: '2800'
|
||||
}
|
||||
],
|
||||
},
|
||||
format: createSuccessfulRemoteDataObject$(allFormats[1]),
|
||||
_links: {
|
||||
self: 'bitstream-selflink'
|
||||
},
|
||||
bundle: createSuccessfulRemoteDataObject$({
|
||||
item: createSuccessfulRemoteDataObject$(Object.assign(new Item(), {
|
||||
uuid: 'some-uuid',
|
||||
firstMetadataValue(keyOrKeys: string | string[], valueFilter?: MetadataValueFilter): string {
|
||||
return 'True';
|
||||
}
|
||||
}))
|
||||
})
|
||||
});
|
||||
bitstreamService = jasmine.createSpyObj('bitstreamService', {
|
||||
findById: createSuccessfulRemoteDataObject$(bitstream),
|
||||
update: createSuccessfulRemoteDataObject$(bitstream),
|
||||
updateFormat: createSuccessfulRemoteDataObject$(bitstream),
|
||||
commitUpdates: {},
|
||||
patch: {}
|
||||
});
|
||||
|
||||
dsoNameService = jasmine.createSpyObj('dsoNameService', {
|
||||
getName: bundleName
|
||||
});
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [TranslateModule.forRoot(), RouterTestingModule],
|
||||
declarations: [EditBitstreamPageComponent, FileSizePipe, VarDirective],
|
||||
providers: [
|
||||
{provide: NotificationsService, useValue: notificationsService},
|
||||
{provide: DynamicFormService, useValue: formService},
|
||||
{
|
||||
provide: ActivatedRoute,
|
||||
useValue: {
|
||||
data: observableOf({bitstream: createSuccessfulRemoteDataObject(bitstream)}),
|
||||
snapshot: {queryParams: {}}
|
||||
}
|
||||
},
|
||||
{provide: BitstreamDataService, useValue: bitstreamService},
|
||||
{provide: DSONameService, useValue: dsoNameService},
|
||||
{provide: BitstreamFormatDataService, useValue: bitstreamFormatService},
|
||||
ChangeDetectorRef
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(EditBitstreamPageComponent);
|
||||
comp = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
router = TestBed.inject(Router);
|
||||
spyOn(router, 'navigate');
|
||||
});
|
||||
|
||||
|
||||
describe('on startup', () => {
|
||||
let rawForm;
|
||||
|
||||
beforeEach(() => {
|
||||
rawForm = comp.formGroup.getRawValue();
|
||||
});
|
||||
it('should set isIIIF to true', () => {
|
||||
expect(comp.isIIIF).toBeTrue();
|
||||
});
|
||||
it('should fill in the iiif label', () => {
|
||||
expect(rawForm.iiifLabelContainer.iiifLabel).toEqual('chapter one');
|
||||
});
|
||||
it('should fill in the iiif toc', () => {
|
||||
expect(rawForm.iiifTocContainer.iiifToc).toEqual('chapter one');
|
||||
});
|
||||
it('should fill in the iiif width', () => {
|
||||
expect(rawForm.iiifWidthContainer.iiifWidth).toEqual('2400');
|
||||
});
|
||||
it('should fill in the iiif height', () => {
|
||||
expect(rawForm.iiifHeightContainer.iiifHeight).toEqual('2800');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('ignore OTHERCONTENT bundle', () => {
|
||||
|
||||
const bundleName = 'OTHERCONTENT';
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
|
||||
bitstream = Object.assign(new Bitstream(), {
|
||||
metadata: {
|
||||
'dc.description': [
|
||||
{
|
||||
value: 'Bitstream description'
|
||||
}
|
||||
],
|
||||
'dc.title': [
|
||||
{
|
||||
value: 'Bitstream title'
|
||||
}
|
||||
],
|
||||
'iiif.label': [
|
||||
{
|
||||
value: 'chapter one'
|
||||
}
|
||||
],
|
||||
'iiif.toc': [
|
||||
{
|
||||
value: 'chapter one'
|
||||
}
|
||||
],
|
||||
'iiif.image.width': [
|
||||
{
|
||||
value: '2400'
|
||||
}
|
||||
],
|
||||
'iiif.image.height': [
|
||||
{
|
||||
value: '2800'
|
||||
}
|
||||
],
|
||||
},
|
||||
format: createSuccessfulRemoteDataObject$(allFormats[2]),
|
||||
_links: {
|
||||
self: 'bitstream-selflink'
|
||||
},
|
||||
bundle: createSuccessfulRemoteDataObject$({
|
||||
item: createSuccessfulRemoteDataObject$(Object.assign(new Item(), {
|
||||
uuid: 'some-uuid',
|
||||
firstMetadataValue(keyOrKeys: string | string[], valueFilter?: MetadataValueFilter): string {
|
||||
return 'True';
|
||||
}
|
||||
}))
|
||||
})
|
||||
});
|
||||
bitstreamService = jasmine.createSpyObj('bitstreamService', {
|
||||
findById: createSuccessfulRemoteDataObject$(bitstream),
|
||||
update: createSuccessfulRemoteDataObject$(bitstream),
|
||||
updateFormat: createSuccessfulRemoteDataObject$(bitstream),
|
||||
commitUpdates: {},
|
||||
patch: {}
|
||||
});
|
||||
|
||||
dsoNameService = jasmine.createSpyObj('dsoNameService', {
|
||||
getName: bundleName
|
||||
});
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [TranslateModule.forRoot(), RouterTestingModule],
|
||||
declarations: [EditBitstreamPageComponent, FileSizePipe, VarDirective],
|
||||
providers: [
|
||||
{provide: NotificationsService, useValue: notificationsService},
|
||||
{provide: DynamicFormService, useValue: formService},
|
||||
{provide: ActivatedRoute,
|
||||
useValue: {
|
||||
data: observableOf({bitstream: createSuccessfulRemoteDataObject(bitstream)}),
|
||||
snapshot: {queryParams: {}}
|
||||
}
|
||||
},
|
||||
{provide: BitstreamDataService, useValue: bitstreamService},
|
||||
{provide: DSONameService, useValue: dsoNameService},
|
||||
{provide: BitstreamFormatDataService, useValue: bitstreamFormatService},
|
||||
ChangeDetectorRef
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(EditBitstreamPageComponent);
|
||||
comp = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
router = TestBed.inject(Router);
|
||||
spyOn(router, 'navigate');
|
||||
});
|
||||
|
||||
describe('EditBitstreamPageComponent with IIIF fields', () => {
|
||||
let rawForm;
|
||||
|
||||
beforeEach(() => {
|
||||
rawForm = comp.formGroup.getRawValue();
|
||||
});
|
||||
|
||||
it('should NOT set isIIIF to true', () => {
|
||||
expect(comp.isIIIF).toBeFalse();
|
||||
});
|
||||
it('should put the \"IIIF Label\" input not to be shown', () => {
|
||||
expect(rawForm.iiifLabelContainer).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
@@ -1,16 +1,27 @@
|
||||
import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
OnDestroy,
|
||||
OnInit
|
||||
} from '@angular/core';
|
||||
import { Bitstream } from '../../core/shared/bitstream.model';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { map, mergeMap, switchMap } from 'rxjs/operators';
|
||||
import { combineLatest as observableCombineLatest, Observable, of as observableOf, Subscription } from 'rxjs';
|
||||
import {
|
||||
combineLatest,
|
||||
combineLatest as observableCombineLatest,
|
||||
Observable,
|
||||
of as observableOf,
|
||||
Subscription
|
||||
} from 'rxjs';
|
||||
import {
|
||||
DynamicFormControlModel,
|
||||
DynamicFormGroupModel,
|
||||
DynamicFormLayout,
|
||||
DynamicFormService,
|
||||
DynamicInputModel,
|
||||
DynamicSelectModel,
|
||||
DynamicTextAreaModel
|
||||
DynamicSelectModel
|
||||
} from '@ng-dynamic-forms/core';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
@@ -28,13 +39,19 @@ import { NotificationsService } from '../../shared/notifications/notifications.s
|
||||
import { BitstreamFormatDataService } from '../../core/data/bitstream-format-data.service';
|
||||
import { BitstreamFormat } from '../../core/shared/bitstream-format.model';
|
||||
import { BitstreamFormatSupportLevel } from '../../core/shared/bitstream-format-support-level';
|
||||
import { hasValue, isNotEmpty } from '../../shared/empty.util';
|
||||
import { hasValue, isNotEmpty, isEmpty } from '../../shared/empty.util';
|
||||
import { Metadata } from '../../core/shared/metadata.utils';
|
||||
import { Location } from '@angular/common';
|
||||
import { RemoteData } from '../../core/data/remote-data';
|
||||
import { PaginatedList } from '../../core/data/paginated-list.model';
|
||||
import { getEntityEditRoute, getItemEditRoute } from '../../item-page/item-page-routing-paths';
|
||||
import { Bundle } from '../../core/shared/bundle.model';
|
||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||
import { Item } from '../../core/shared/item.model';
|
||||
import {
|
||||
DsDynamicInputModel
|
||||
} from '../../shared/form/builder/ds-dynamic-form-ui/models/ds-dynamic-input.model';
|
||||
import { DsDynamicTextAreaModel } from '../../shared/form/builder/ds-dynamic-form-ui/models/ds-dynamic-textarea.model';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-edit-bitstream-page',
|
||||
@@ -94,6 +111,26 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
|
||||
*/
|
||||
NOTIFICATIONS_PREFIX = 'bitstream.edit.notifications.';
|
||||
|
||||
/**
|
||||
* IIIF image width metadata key
|
||||
*/
|
||||
IMAGE_WIDTH_METADATA = 'iiif.image.width';
|
||||
|
||||
/**
|
||||
* IIIF image height metadata key
|
||||
*/
|
||||
IMAGE_HEIGHT_METADATA = 'iiif.image.height';
|
||||
|
||||
/**
|
||||
* IIIF table of contents metadata key
|
||||
*/
|
||||
IIIF_TOC_METADATA = 'iiif.toc';
|
||||
|
||||
/**
|
||||
* IIIF label metadata key
|
||||
*/
|
||||
IIIF_LABEL_METADATA = 'iiif.label';
|
||||
|
||||
/**
|
||||
* Options for fetching all bitstream formats
|
||||
*/
|
||||
@@ -102,7 +139,8 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
|
||||
/**
|
||||
* The Dynamic Input Model for the file's name
|
||||
*/
|
||||
fileNameModel = new DynamicInputModel({
|
||||
fileNameModel = new DsDynamicInputModel({
|
||||
hasSelectableMetadata: false, metadataFields: [], repeatable: false, submissionId: '',
|
||||
id: 'fileName',
|
||||
name: 'fileName',
|
||||
required: true,
|
||||
@@ -120,12 +158,14 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
|
||||
primaryBitstreamModel = new DynamicCustomSwitchModel({
|
||||
id: 'primaryBitstream',
|
||||
name: 'primaryBitstream'
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* The Dynamic TextArea Model for the file's description
|
||||
*/
|
||||
descriptionModel = new DynamicTextAreaModel({
|
||||
descriptionModel = new DsDynamicTextAreaModel({
|
||||
hasSelectableMetadata: false, metadataFields: [], repeatable: false, submissionId: '',
|
||||
id: 'description',
|
||||
name: 'description',
|
||||
rows: 10
|
||||
@@ -147,10 +187,87 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
|
||||
name: 'newFormat'
|
||||
});
|
||||
|
||||
/**
|
||||
* The Dynamic Input Model for the iiif label
|
||||
*/
|
||||
iiifLabelModel = new DsDynamicInputModel({
|
||||
hasSelectableMetadata: false, metadataFields: [], repeatable: false, submissionId: '',
|
||||
id: 'iiifLabel',
|
||||
name: 'iiifLabel'
|
||||
},
|
||||
{
|
||||
grid: {
|
||||
host: 'col col-lg-6 d-inline-block'
|
||||
}
|
||||
});
|
||||
iiifLabelContainer = new DynamicFormGroupModel({
|
||||
id: 'iiifLabelContainer',
|
||||
group: [this.iiifLabelModel]
|
||||
},{
|
||||
grid: {
|
||||
host: 'form-row'
|
||||
}
|
||||
});
|
||||
|
||||
iiifTocModel = new DsDynamicInputModel({
|
||||
hasSelectableMetadata: false, metadataFields: [], repeatable: false, submissionId: '',
|
||||
id: 'iiifToc',
|
||||
name: 'iiifToc',
|
||||
},{
|
||||
grid: {
|
||||
host: 'col col-lg-6 d-inline-block'
|
||||
}
|
||||
});
|
||||
iiifTocContainer = new DynamicFormGroupModel({
|
||||
id: 'iiifTocContainer',
|
||||
group: [this.iiifTocModel]
|
||||
},{
|
||||
grid: {
|
||||
host: 'form-row'
|
||||
}
|
||||
});
|
||||
|
||||
iiifWidthModel = new DsDynamicInputModel({
|
||||
hasSelectableMetadata: false, metadataFields: [], repeatable: false, submissionId: '',
|
||||
id: 'iiifWidth',
|
||||
name: 'iiifWidth',
|
||||
},{
|
||||
grid: {
|
||||
host: 'col col-lg-6 d-inline-block'
|
||||
}
|
||||
});
|
||||
iiifWidthContainer = new DynamicFormGroupModel({
|
||||
id: 'iiifWidthContainer',
|
||||
group: [this.iiifWidthModel]
|
||||
},{
|
||||
grid: {
|
||||
host: 'form-row'
|
||||
}
|
||||
});
|
||||
|
||||
iiifHeightModel = new DsDynamicInputModel({
|
||||
hasSelectableMetadata: false, metadataFields: [], repeatable: false, submissionId: '',
|
||||
id: 'iiifHeight',
|
||||
name: 'iiifHeight'
|
||||
},{
|
||||
grid: {
|
||||
host: 'col col-lg-6 d-inline-block'
|
||||
}
|
||||
});
|
||||
iiifHeightContainer = new DynamicFormGroupModel({
|
||||
id: 'iiifHeightContainer',
|
||||
group: [this.iiifHeightModel]
|
||||
},{
|
||||
grid: {
|
||||
host: 'form-row'
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* All input models in a simple array for easier iterations
|
||||
*/
|
||||
inputModels = [this.fileNameModel, this.primaryBitstreamModel, this.descriptionModel, this.selectedFormatModel, this.newFormatModel];
|
||||
inputModels = [this.fileNameModel, this.primaryBitstreamModel, this.descriptionModel, this.selectedFormatModel,
|
||||
this.newFormatModel];
|
||||
|
||||
/**
|
||||
* The dynamic form fields used for editing the information of a bitstream
|
||||
@@ -163,6 +280,10 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
|
||||
this.fileNameModel,
|
||||
this.primaryBitstreamModel
|
||||
]
|
||||
},{
|
||||
grid: {
|
||||
host: 'form-row'
|
||||
}
|
||||
}),
|
||||
new DynamicFormGroupModel({
|
||||
id: 'descriptionContainer',
|
||||
@@ -254,18 +375,27 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
|
||||
*/
|
||||
entityType: string;
|
||||
|
||||
/**
|
||||
* Set to true when the parent item supports IIIF.
|
||||
*/
|
||||
isIIIF = false;
|
||||
|
||||
|
||||
/**
|
||||
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||
* @type {Array}
|
||||
*/
|
||||
protected subs: Subscription[] = [];
|
||||
|
||||
|
||||
constructor(private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private location: Location,
|
||||
private formService: DynamicFormService,
|
||||
private translate: TranslateService,
|
||||
private bitstreamService: BitstreamDataService,
|
||||
private dsoNameService: DSONameService,
|
||||
private notificationsService: NotificationsService,
|
||||
private bitstreamFormatService: BitstreamFormatDataService) {
|
||||
}
|
||||
@@ -277,7 +407,6 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
|
||||
* - Translate the form labels and hints
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.formGroup = this.formService.createFormGroup(this.formModel);
|
||||
|
||||
this.itemId = this.route.snapshot.queryParams.itemId;
|
||||
this.entityType = this.route.snapshot.queryParams.entityType;
|
||||
@@ -301,13 +430,10 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
|
||||
).subscribe(([bitstream, allFormats]) => {
|
||||
this.bitstream = bitstream as Bitstream;
|
||||
this.formats = allFormats.page;
|
||||
this.updateFormatModel();
|
||||
this.updateForm(this.bitstream);
|
||||
this.setIiifStatus(this.bitstream);
|
||||
})
|
||||
);
|
||||
|
||||
this.updateFieldTranslations();
|
||||
|
||||
this.subs.push(
|
||||
this.translate.onLangChange
|
||||
.subscribe(() => {
|
||||
@@ -316,6 +442,16 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the form.
|
||||
*/
|
||||
setForm() {
|
||||
this.formGroup = this.formService.createFormGroup(this.formModel);
|
||||
this.updateFormatModel();
|
||||
this.updateForm(this.bitstream);
|
||||
this.updateFieldTranslations();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the current form values with bitstream properties
|
||||
* @param bitstream
|
||||
@@ -333,6 +469,22 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
|
||||
newFormat: hasValue(bitstream.firstMetadata('dc.format')) ? bitstream.firstMetadata('dc.format').value : undefined
|
||||
}
|
||||
});
|
||||
if (this.isIIIF) {
|
||||
this.formGroup.patchValue({
|
||||
iiifLabelContainer: {
|
||||
iiifLabel: bitstream.firstMetadataValue(this.IIIF_LABEL_METADATA)
|
||||
},
|
||||
iiifTocContainer: {
|
||||
iiifToc: bitstream.firstMetadataValue(this.IIIF_TOC_METADATA)
|
||||
},
|
||||
iiifWidthContainer: {
|
||||
iiifWidth: bitstream.firstMetadataValue(this.IMAGE_WIDTH_METADATA)
|
||||
},
|
||||
iiifHeightContainer: {
|
||||
iiifHeight: bitstream.firstMetadataValue(this.IMAGE_HEIGHT_METADATA)
|
||||
}
|
||||
});
|
||||
}
|
||||
this.bitstream.format.pipe(
|
||||
getAllSucceededRemoteDataPayload()
|
||||
).subscribe((format: BitstreamFormat) => {
|
||||
@@ -467,6 +619,32 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
|
||||
const primary = rawForm.fileNamePrimaryContainer.primaryBitstream;
|
||||
Metadata.setFirstValue(newMetadata, 'dc.title', rawForm.fileNamePrimaryContainer.fileName);
|
||||
Metadata.setFirstValue(newMetadata, 'dc.description', rawForm.descriptionContainer.description);
|
||||
if (this.isIIIF) {
|
||||
// It's helpful to remove these metadata elements entirely when the form value is empty.
|
||||
// This avoids potential issues on the REST side and makes it possible to do things like
|
||||
// remove an existing "table of contents" entry.
|
||||
if (isEmpty(rawForm.iiifLabelContainer.iiifLabel)) {
|
||||
|
||||
delete newMetadata[this.IIIF_LABEL_METADATA];
|
||||
} else {
|
||||
Metadata.setFirstValue(newMetadata, this.IIIF_LABEL_METADATA, rawForm.iiifLabelContainer.iiifLabel);
|
||||
}
|
||||
if (isEmpty(rawForm.iiifTocContainer.iiifToc)) {
|
||||
delete newMetadata[this.IIIF_TOC_METADATA];
|
||||
} else {
|
||||
Metadata.setFirstValue(newMetadata, this.IIIF_TOC_METADATA, rawForm.iiifTocContainer.iiifToc);
|
||||
}
|
||||
if (isEmpty(rawForm.iiifWidthContainer.iiifWidth)) {
|
||||
delete newMetadata[this.IMAGE_WIDTH_METADATA];
|
||||
} else {
|
||||
Metadata.setFirstValue(newMetadata, this.IMAGE_WIDTH_METADATA, rawForm.iiifWidthContainer.iiifWidth);
|
||||
}
|
||||
if (isEmpty(rawForm.iiifHeightContainer.iiifHeight)) {
|
||||
delete newMetadata[this.IMAGE_HEIGHT_METADATA];
|
||||
} else {
|
||||
Metadata.setFirstValue(newMetadata, this.IMAGE_HEIGHT_METADATA, rawForm.iiifHeightContainer.iiifHeight);
|
||||
}
|
||||
}
|
||||
if (isNotEmpty(rawForm.formatContainer.newFormat)) {
|
||||
Metadata.setFirstValue(newMetadata, 'dc.format', rawForm.formatContainer.newFormat);
|
||||
}
|
||||
@@ -497,6 +675,58 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the parent item is iiif-enabled. Checks bitstream mimetype to be
|
||||
* sure it's an image, excluding bitstreams in the THUMBNAIL or OTHERCONTENT bundles.
|
||||
* @param bitstream
|
||||
*/
|
||||
setIiifStatus(bitstream: Bitstream) {
|
||||
|
||||
const regexExcludeBundles = /OTHERCONTENT|THUMBNAIL|LICENSE/;
|
||||
const regexIIIFItem = /true|yes/i;
|
||||
|
||||
const isImage$ = this.bitstream.format.pipe(
|
||||
getFirstSucceededRemoteData(),
|
||||
map((format: RemoteData<BitstreamFormat>) => format.payload.mimetype.includes('image/')));
|
||||
|
||||
const isIIIFBundle$ = this.bitstream.bundle.pipe(
|
||||
getFirstSucceededRemoteData(),
|
||||
map((bundle: RemoteData<Bundle>) =>
|
||||
this.dsoNameService.getName(bundle.payload).match(regexExcludeBundles) == null));
|
||||
|
||||
const isEnabled$ = this.bitstream.bundle.pipe(
|
||||
getFirstSucceededRemoteData(),
|
||||
map((bundle: RemoteData<Bundle>) => bundle.payload.item.pipe(
|
||||
getFirstSucceededRemoteData(),
|
||||
map((item: RemoteData<Item>) =>
|
||||
(item.payload.firstMetadataValue('dspace.iiif.enabled') &&
|
||||
item.payload.firstMetadataValue('dspace.iiif.enabled').match(regexIIIFItem) !== null)
|
||||
))));
|
||||
|
||||
const iiifSub = combineLatest(
|
||||
isImage$,
|
||||
isIIIFBundle$,
|
||||
isEnabled$
|
||||
).subscribe(([isImage, isIIIFBundle, isEnabled]) => {
|
||||
if (isImage && isIIIFBundle && isEnabled) {
|
||||
this.isIIIF = true;
|
||||
this.inputModels.push(this.iiifLabelModel);
|
||||
this.formModel.push(this.iiifLabelContainer);
|
||||
this.inputModels.push(this.iiifTocModel);
|
||||
this.formModel.push(this.iiifTocContainer);
|
||||
this.inputModels.push(this.iiifWidthModel);
|
||||
this.formModel.push(this.iiifWidthContainer);
|
||||
this.inputModels.push(this.iiifHeightModel);
|
||||
this.formModel.push(this.iiifHeightContainer);
|
||||
}
|
||||
this.setForm();
|
||||
this.changeDetectorRef.detectChanges();
|
||||
});
|
||||
|
||||
this.subs.push(iiifSub);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe from open subscriptions
|
||||
*/
|
||||
|
@@ -587,6 +587,23 @@
|
||||
|
||||
"bitstream.edit.notifications.error.format.title": "An error occurred saving the bitstream's format",
|
||||
|
||||
"bitstream.edit.form.iiifLabel.label": "IIIF Label",
|
||||
|
||||
"bitstream.edit.form.iiifLabel.hint": "Canvas label for this image. If not provided default label will be used.",
|
||||
|
||||
"bitstream.edit.form.iiifToc.label": "IIIF Table of Contents",
|
||||
|
||||
"bitstream.edit.form.iiifToc.hint": "Adding text here makes this the start of a new table of contents range.",
|
||||
|
||||
"bitstream.edit.form.iiifWidth.label": "IIIF Canvas Width",
|
||||
|
||||
"bitstream.edit.form.iiifWidth.hint": "The canvas width should usually match the image width.",
|
||||
|
||||
"bitstream.edit.form.iiifHeight.label": "IIIF Canvas Height",
|
||||
|
||||
"bitstream.edit.form.iiifHeight.hint": "The canvas height should usually match the image height.",
|
||||
|
||||
|
||||
"bitstream.edit.notifications.saved.content": "Your changes to this bitstream were saved.",
|
||||
|
||||
"bitstream.edit.notifications.saved.title": "Bitstream saved",
|
||||
|
Reference in New Issue
Block a user