From 84975d7a2b7b6ae3b547da9d0780bc58f4979e50 Mon Sep 17 00:00:00 2001 From: mdelez <60604010+mdelez@users.noreply.github.com> Date: Wed, 25 May 2022 15:53:06 +0200 Subject: [PATCH] feat(text-file): add support for text file representations (DEV-920) (#751) * feat(text-file): add support for text file representations * fix(upload): add text/csv MIME type --- package-lock.json | 14 +- package.json | 2 +- src/app/app.module.ts | 4 +- src/app/main/status/status.component.ts | 2 +- .../create-link-resource.component.ts | 8 +- .../archive/archive.component.html | 2 +- .../representation/text/text.component.html | 17 +++ .../representation/text/text.component.scss | 0 .../text/text.component.spec.ts | 109 ++++++++++++++ .../representation/text/text.component.ts | 140 ++++++++++++++++++ .../upload/upload.component.html | 9 +- .../representation/upload/upload.component.ts | 21 ++- .../resource-instance-form.component.ts | 8 +- .../resource/resource.component.html | 6 + .../workspace/resource/resource.component.ts | 9 +- src/assets/style/_elements.scss | 3 +- 16 files changed, 333 insertions(+), 21 deletions(-) create mode 100644 src/app/workspace/resource/representation/text/text.component.html create mode 100644 src/app/workspace/resource/representation/text/text.component.scss create mode 100644 src/app/workspace/resource/representation/text/text.component.spec.ts create mode 100644 src/app/workspace/resource/representation/text/text.component.ts diff --git a/package-lock.json b/package-lock.json index 90369ac870..0df2013836 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "@angular/platform-browser-dynamic": "^13.2.6", "@angular/router": "^13.2.6", "@ckeditor/ckeditor5-angular": "^2.0.2", - "@dasch-swiss/dsp-js": "^7.2.1", + "@dasch-swiss/dsp-js": "^7.3.0", "@datadog/browser-rum": "^3.11.0", "@ngx-translate/core": "^13.0.0", "@ngx-translate/http-loader": "6.0.0", @@ -2425,9 +2425,9 @@ } }, "node_modules/@dasch-swiss/dsp-js": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/@dasch-swiss/dsp-js/-/dsp-js-7.2.1.tgz", - "integrity": "sha512-rvHx0PBmVwwPOnk9E4Rui3obY6glWBXmsk74s8b0hNdVePyxPk69wC2lKBAyHx8aX9x96ebTP9+a1jXmb//cdg==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@dasch-swiss/dsp-js/-/dsp-js-7.3.0.tgz", + "integrity": "sha512-mtE9zwEX58A3oj6btmLxv6DbLBKtpB4W3UZxjhGDO29aKEqQIC2kNqS7YjQijXo0ZSc1P9/gv0uaZ9P8QcU1YQ==", "dependencies": { "@babel/helper-compilation-targets": "^7.16.7", "@types/jsonld": "^1.5.6", @@ -17117,9 +17117,9 @@ } }, "@dasch-swiss/dsp-js": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/@dasch-swiss/dsp-js/-/dsp-js-7.2.1.tgz", - "integrity": "sha512-rvHx0PBmVwwPOnk9E4Rui3obY6glWBXmsk74s8b0hNdVePyxPk69wC2lKBAyHx8aX9x96ebTP9+a1jXmb//cdg==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@dasch-swiss/dsp-js/-/dsp-js-7.3.0.tgz", + "integrity": "sha512-mtE9zwEX58A3oj6btmLxv6DbLBKtpB4W3UZxjhGDO29aKEqQIC2kNqS7YjQijXo0ZSc1P9/gv0uaZ9P8QcU1YQ==", "requires": { "@babel/helper-compilation-targets": "^7.16.7", "@types/jsonld": "^1.5.6", diff --git a/package.json b/package.json index 716ee55ef0..7649186ef3 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@angular/platform-browser-dynamic": "^13.2.6", "@angular/router": "^13.2.6", "@ckeditor/ckeditor5-angular": "^2.0.2", - "@dasch-swiss/dsp-js": "^7.2.1", + "@dasch-swiss/dsp-js": "^7.3.0", "@datadog/browser-rum": "^3.11.0", "@ngx-translate/core": "^13.0.0", "@ngx-translate/http-loader": "6.0.0", diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 2012f2af5a..04a6369c08 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -160,6 +160,7 @@ import { ExpertSearchComponent } from './workspace/search/expert-search/expert-s import { FulltextSearchComponent } from './workspace/search/fulltext-search/fulltext-search.component'; import { SearchPanelComponent } from './workspace/search/search-panel/search-panel.component'; import { HintComponent } from './main/action/hint/hint.component'; +import { TextComponent } from './workspace/resource/representation/text/text.component'; // translate: AoT requires an exported function for factories export function httpLoaderFactory(httpClient: HttpClient) { @@ -306,7 +307,8 @@ export function httpLoaderFactory(httpClient: HttpClient) { UsersListComponent, VideoComponent, VideoPreviewComponent, - HintComponent + HintComponent, + TextComponent ], imports: [ AngularSplitModule.forRoot(), diff --git a/src/app/main/status/status.component.ts b/src/app/main/status/status.component.ts index da3e63dc6e..0b6beeadbf 100644 --- a/src/app/main/status/status.component.ts +++ b/src/app/main/status/status.component.ts @@ -25,7 +25,7 @@ export class StatusComponent implements OnInit { @Input() comment?: string; @Input() url?: string; - @Input() representation?: 'archive' | 'audio' | 'document' | 'still-image' | 'video'; + @Input() representation?: 'archive' | 'audio' | 'document' | 'still-image' | 'video' | 'text'; refresh = false; diff --git a/src/app/workspace/resource/operations/create-link-resource/create-link-resource.component.ts b/src/app/workspace/resource/operations/create-link-resource/create-link-resource.component.ts index e3731dc1fd..2d60e522c6 100644 --- a/src/app/workspace/resource/operations/create-link-resource/create-link-resource.component.ts +++ b/src/app/workspace/resource/operations/create-link-resource/create-link-resource.component.ts @@ -64,7 +64,9 @@ export class CreateLinkResourceComponent implements OnInit { prop.id !== Constants.HasStillImageFileValue && prop.id !== Constants.HasDocumentFileValue && prop.id !== Constants.HasAudioFileValue && - prop.id !== Constants.HasArchiveFileValue + prop.id !== Constants.HasArchiveFileValue && + prop.id !== Constants.HasMovingImageFileValue && + prop.id !== Constants.HasTextFileValue ); if (onto.properties[Constants.HasStillImageFileValue]) { @@ -75,6 +77,10 @@ export class CreateLinkResourceComponent implements OnInit { this.hasFileValue = 'audio'; } else if (onto.properties[Constants.HasArchiveFileValue]) { this.hasFileValue = 'archive'; + } else if (onto.properties[Constants.HasMovingImageFileValue]) { + this.hasFileValue = 'movingImage'; + } else if (onto.properties[Constants.HasTextFileValue]) { + this.hasFileValue = 'text'; } else { this.hasFileValue = undefined; } diff --git a/src/app/workspace/resource/representation/archive/archive.component.html b/src/app/workspace/resource/representation/archive/archive.component.html index 7be0f4698d..755586342d 100644 --- a/src/app/workspace/resource/representation/archive/archive.component.html +++ b/src/app/workspace/resource/representation/archive/archive.component.html @@ -1,6 +1,6 @@
- + + +
+
+ No valid file url found for this resource. +
diff --git a/src/app/workspace/resource/representation/text/text.component.scss b/src/app/workspace/resource/representation/text/text.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/workspace/resource/representation/text/text.component.spec.ts b/src/app/workspace/resource/representation/text/text.component.spec.ts new file mode 100644 index 0000000000..260edd2c21 --- /dev/null +++ b/src/app/workspace/resource/representation/text/text.component.spec.ts @@ -0,0 +1,109 @@ +import { HarnessLoader } from '@angular/cdk/testing'; +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { Component, OnInit, ViewChild } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MatButtonHarness } from '@angular/material/button/testing'; +import { MatDialogModule } from '@angular/material/dialog'; +import { MatSnackBarModule } from '@angular/material/snack-bar'; +import { KnoraApiConnection } from '@dasch-swiss/dsp-js'; +import { AppInitService } from 'src/app/app-init.service'; +import { DspApiConfigToken, DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens'; +import { TestConfig } from 'test.config'; +import { FileRepresentation } from '../file-representation'; + +import { TextComponent } from './text.component'; + +const textFileValue = { + 'arkUrl': 'http://0.0.0.0:3336/ark:/72163/1/9876/=wcU1HzYTEKbJCYPybyKmAs/Kp81r_BPTHKa4oSd5iIxXgd', + 'attachedToUser': 'http://rdfh.ch/users/root', + 'fileUrl': 'http://0.0.0.0:1024/9876/Jjic1ixccX7-BUHCAFNlEts.txt/file', + 'filename': 'Jjic1ixccX7-BUHCAFNlEts.txt', + 'hasPermissions': 'CR knora-admin:ProjectAdmin|M knora-admin:ProjectMember', + 'id': 'http://rdfh.ch/9876/-wcU1HzYTEKbJCYPybyKmA/values/95Ny4a1_S6ey5JQZWjf07g', + 'property': 'http://api.knora.org/ontology/knora-api/v2#hasTextFileValue', + 'propertyComment': 'Connects a Representation to a text file', + 'propertyLabel': 'hat Textdatei', + 'strval': 'http://0.0.0.0:1024/9876/Jjic1ixccX7-BUHCAFNlEts.txt/file', + 'type': 'http://api.knora.org/ontology/knora-api/v2#TextFileValue', + 'userHasPermission': 'CR', + 'uuid': 'Kp81r_BPTHKa4oSd5iIxXg', + 'valueCreationDate': '2022-05-25T09:20:19.907631398Z', + 'valueHasComment': undefined, + 'versionArkUrl': 'http://0.0.0.0:3336/ark:/72163/1/9876/=wcU1HzYTEKbJCYPybyKmAs/Kp81r_BPTHKa4oSd5iIxXgd.20220525T092019907631398Z' +}; + +@Component({ + template: ` + + ` +}) +class TestHostComponent implements OnInit { + + @ViewChild(TextComponent) textComp: TextComponent; + + textFileRepresentation: FileRepresentation; + + ngOnInit() { + + this.textFileRepresentation = new FileRepresentation(textFileValue); + } +} +describe('TextComponent', () => { + let testHostComponent: TestHostComponent; + let testHostFixture: ComponentFixture; + let loader: HarnessLoader; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + TextComponent, + TestHostComponent + ], + imports: [ + HttpClientTestingModule, + MatDialogModule, + MatSnackBarModule + ], + providers: [ + AppInitService, + { + provide: DspApiConfigToken, + useValue: TestConfig.ApiConfig + }, + { + provide: DspApiConnectionToken, + useValue: new KnoraApiConnection(TestConfig.ApiConfig) + } + ] + }) + .compileComponents(); + }); + + beforeEach(() => { + testHostFixture = TestBed.createComponent(TestHostComponent); + testHostComponent = testHostFixture.componentInstance; + loader = TestbedHarnessEnvironment.loader(testHostFixture); + testHostFixture.detectChanges(); + expect(testHostComponent).toBeTruthy(); + }); + + it('should have a file url', () => { + expect(testHostComponent.textFileRepresentation.fileValue.fileUrl).toEqual('http://0.0.0.0:1024/9876/Jjic1ixccX7-BUHCAFNlEts.txt/file'); + }); + + it('should show a download button if the file url is provided', async () => { + const downloadButtonElement = await loader.getHarness(MatButtonHarness.with({ selector: '.download' })); + + expect(downloadButtonElement).toBeTruthy(); + }); + + it('should NOT show a download button if the file url is NOT provided', async () => { + testHostComponent.textFileRepresentation = undefined; + testHostFixture.detectChanges(); + + const downloadButtonElement = await loader.getAllHarnesses(MatButtonHarness.with({ selector: '.download' })); + + expect(downloadButtonElement.length).toEqual(0); + }); +}); diff --git a/src/app/workspace/resource/representation/text/text.component.ts b/src/app/workspace/resource/representation/text/text.component.ts new file mode 100644 index 0000000000..f49f39e5c2 --- /dev/null +++ b/src/app/workspace/resource/representation/text/text.component.ts @@ -0,0 +1,140 @@ +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { AfterViewInit, Component, EventEmitter, Inject, Input, OnInit, Output } from '@angular/core'; +import { MatDialog, MatDialogConfig } from '@angular/material/dialog'; +import { ApiResponseError, Constants, KnoraApiConnection, ReadTextFileValue, ReadResource, UpdateFileValue, UpdateResource, UpdateValue, WriteValueResponse } from '@dasch-swiss/dsp-js'; +import { mergeMap } from 'rxjs/operators'; +import { DspApiConnectionToken } from 'src/app/main/declarations/dsp-api-tokens'; +import { DialogComponent } from 'src/app/main/dialog/dialog.component'; +import { ErrorHandlerService } from 'src/app/main/services/error-handler.service'; +import { EmitEvent, Events, UpdatedFileEventValue, ValueOperationEventService } from '../../services/value-operation-event.service'; +import { FileRepresentation } from '../file-representation'; +import { RepresentationService } from '../representation.service'; + +@Component({ + selector: 'app-text', + templateUrl: './text.component.html', + styleUrls: ['./text.component.scss'] +}) +export class TextComponent implements OnInit, AfterViewInit { + + @Input() src: FileRepresentation; + + @Input() parentResource: ReadResource; + + @Output() loaded = new EventEmitter(); + + originalFilename: string; + + failedToLoad = false; + + constructor( + @Inject(DspApiConnectionToken) private _dspApiConnection: KnoraApiConnection, + private readonly _http: HttpClient, + private _dialog: MatDialog, + private _errorHandler: ErrorHandlerService, + private _rs: RepresentationService, + private _valueOperationEventService: ValueOperationEventService + ) { } + + ngOnInit(): void { + this._getOriginalFilename(); + this.failedToLoad = !this._rs.doesFileExist(this.src.fileValue.fileUrl); + } + + ngAfterViewInit() { + this.loaded.emit(true); + } + + // https://stackoverflow.com/questions/66986983/angular-10-download-file-from-firebase-link-without-opening-into-new-tab + async downloadText(url: string) { + try { + const res = await this._http.get(url, { responseType: 'blob' }).toPromise(); + this.downloadFile(res); + } catch (e) { + this._errorHandler.showMessage(e); + } + } + + downloadFile(data) { + const url = window.URL.createObjectURL(data); + const e = document.createElement('a'); + e.href = url; + + // set filename + if (this.originalFilename === undefined) { + e.download = url.substr(url.lastIndexOf('/') + 1); + } else { + e.download = this.originalFilename; + } + + document.body.appendChild(e); + e.click(); + document.body.removeChild(e); + } + + openReplaceFileDialog(){ + const propId = this.parentResource.properties[Constants.HasTextFileValue][0].id; + + const dialogConfig: MatDialogConfig = { + width: '800px', + maxHeight: '80vh', + position: { + top: '112px' + }, + data: { mode: 'replaceFile', title: 'Text (csv, txt, xml)', subtitle: 'Update the text file of this resource' , representation: 'text', id: propId }, + disableClose: true + }; + const dialogRef = this._dialog.open( + DialogComponent, + dialogConfig + ); + + dialogRef.afterClosed().subscribe((data) => { + if (data) { + this._replaceFile(data); + } + }); + } + + private _getOriginalFilename() { + const requestOptions = { + headers: new HttpHeaders({ 'Content-Type': 'application/json' }), + withCredentials: true + }; + + const pathToJson = this.src.fileValue.fileUrl.substring(0, this.src.fileValue.fileUrl.lastIndexOf('/')) + '/knora.json'; + + this._http.get(pathToJson, requestOptions).subscribe( + res => { + this.originalFilename = res['originalFilename']; + } + ); + } + + private _replaceFile(file: UpdateFileValue) { + const updateRes = new UpdateResource(); + updateRes.id = this.parentResource.id; + updateRes.type = this.parentResource.type; + updateRes.property = Constants.HasTextFileValue; + updateRes.value = file; + + this._dspApiConnection.v2.values.updateValue(updateRes as UpdateResource).pipe( + mergeMap((res: WriteValueResponse) => this._dspApiConnection.v2.values.getValue(this.parentResource.id, res.uuid)) + ).subscribe( + (res2: ReadResource) => { + this.src.fileValue.fileUrl = (res2.properties[Constants.HasTextFileValue][0] as ReadTextFileValue).fileUrl; + this.src.fileValue.filename = (res2.properties[Constants.HasTextFileValue][0] as ReadTextFileValue).filename; + this.src.fileValue.strval = (res2.properties[Constants.HasTextFileValue][0] as ReadTextFileValue).strval; + + this._getOriginalFilename(); + + this._valueOperationEventService.emit( + new EmitEvent(Events.FileValueUpdated, new UpdatedFileEventValue( + res2.properties[Constants.HasTextFileValue][0]))); + }, + (error: ApiResponseError) => { + this._errorHandler.showMessage(error); + } + ); + } +} diff --git a/src/app/workspace/resource/representation/upload/upload.component.html b/src/app/workspace/resource/representation/upload/upload.component.html index b71bd12cb9..7d45c960bd 100644 --- a/src/app/workspace/resource/representation/upload/upload.component.html +++ b/src/app/workspace/resource/representation/upload/upload.component.html @@ -9,10 +9,13 @@

Upload file
The following file types are supported:
- {{ item | split: '/':1 }} - + + {{ item | split: '/':1 }} + + -  (= mp3) +  mp3 +  csv, txt, xml

diff --git a/src/app/workspace/resource/representation/upload/upload.component.ts b/src/app/workspace/resource/representation/upload/upload.component.ts index 81b1e0a37e..84d677d5a1 100644 --- a/src/app/workspace/resource/representation/upload/upload.component.ts +++ b/src/app/workspace/resource/representation/upload/upload.component.ts @@ -8,12 +8,14 @@ import { CreateFileValue, CreateMovingImageFileValue, CreateStillImageFileValue, + CreateTextFileValue, UpdateArchiveFileValue, UpdateAudioFileValue, UpdateDocumentFileValue, UpdateFileValue, UpdateMovingImageFileValue, - UpdateStillImageFileValue + UpdateStillImageFileValue, + UpdateTextFileValue } from '@dasch-swiss/dsp-js'; import { NotificationService } from 'src/app/main/services/notification.service'; import { UploadedFileResponse, UploadFileService } from './upload-file.service'; @@ -50,6 +52,7 @@ export class UploadComponent implements OnInit { supportedAudioTypes = ['audio/mpeg']; supportedVideoTypes = ['video/mp4']; supportedArchiveTypes = ['application/zip', 'application/x-tar', 'application/gzip']; + supportedTextTypes = ['application/csv', 'application/xml', 'text/csv', 'text/plain', 'text/xml']; constructor( private _fb: FormBuilder, @@ -209,7 +212,7 @@ export class UploadComponent implements OnInit { const filename = this.fileControl.value.internalFilename; - let fileValue: CreateStillImageFileValue | CreateDocumentFileValue | CreateAudioFileValue | CreateArchiveFileValue; + let fileValue: CreateStillImageFileValue | CreateDocumentFileValue | CreateAudioFileValue | CreateArchiveFileValue | CreateMovingImageFileValue | CreateTextFileValue; switch (this.representation) { case 'stillImage': @@ -232,6 +235,10 @@ export class UploadComponent implements OnInit { fileValue = new CreateArchiveFileValue(); break; + case 'text': + fileValue = new CreateTextFileValue(); + break; + default: // --> TODO for UPLOAD: expand with other representation file types break; @@ -256,7 +263,7 @@ export class UploadComponent implements OnInit { const filename = this.fileControl.value.internalFilename; - let fileValue: UpdateStillImageFileValue | UpdateDocumentFileValue | UpdateAudioFileValue | UpdateArchiveFileValue; + let fileValue: UpdateStillImageFileValue | UpdateDocumentFileValue | UpdateAudioFileValue | UpdateArchiveFileValue | UpdateMovingImageFileValue | UpdateTextFileValue; switch (this.representation) { @@ -280,6 +287,10 @@ export class UploadComponent implements OnInit { fileValue = new UpdateArchiveFileValue(); break; + case 'text': + fileValue = new UpdateTextFileValue(); + break; + default: // --> TODO for UPLOAD: expand with other representation file types break; @@ -327,6 +338,10 @@ export class UploadComponent implements OnInit { this.allowedFileTypes = this.supportedArchiveTypes; break; + case 'text': + this.allowedFileTypes = this.supportedTextTypes; + break; + default: this.allowedFileTypes = []; break; diff --git a/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.ts b/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.ts index cad3a1d1da..25d18f71a7 100644 --- a/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.ts +++ b/src/app/workspace/resource/resource-instance-form/resource-instance-form.component.ts @@ -205,6 +205,9 @@ export class ResourceInstanceFormComponent implements OnInit, OnDestroy { break; case 'archive': this.propertiesObj[Constants.HasArchiveFileValue] = [this.fileValue]; + break; + case 'text': + this.propertiesObj[Constants.HasTextFileValue] = [this.fileValue]; } } @@ -392,7 +395,8 @@ export class ResourceInstanceFormComponent implements OnInit, OnDestroy { prop.id !== Constants.HasDocumentFileValue && prop.id !== Constants.HasAudioFileValue && prop.id !== Constants.HasMovingImageFileValue && - prop.id !== Constants.HasArchiveFileValue + prop.id !== Constants.HasArchiveFileValue && + prop.id !== Constants.HasTextFileValue // --> TODO for UPLOAD: expand with other representation file values ); @@ -406,6 +410,8 @@ export class ResourceInstanceFormComponent implements OnInit, OnDestroy { this.hasFileValue = 'movingImage'; } else if (onto.properties[Constants.HasArchiveFileValue]) { this.hasFileValue = 'archive'; + } else if (onto.properties[Constants.HasTextFileValue]) { + this.hasFileValue = 'text'; } else { this.hasFileValue = undefined; } diff --git a/src/app/workspace/resource/resource.component.html b/src/app/workspace/resource/resource.component.html index c6c2c7435e..cfd3a1a958 100644 --- a/src/app/workspace/resource/resource.component.html +++ b/src/app/workspace/resource/resource.component.html @@ -46,6 +46,12 @@ (loaded)="representationLoaded($event)"> + + + The file representation type "{{representationsToDisplay[0].fileValue.type}}" is not yet implemented diff --git a/src/app/workspace/resource/resource.component.ts b/src/app/workspace/resource/resource.component.ts index c7e2d34a5e..884e1684fd 100644 --- a/src/app/workspace/resource/resource.component.ts +++ b/src/app/workspace/resource/resource.component.ts @@ -23,6 +23,7 @@ import { ReadResource, ReadResourceSequence, ReadStillImageFileValue, + ReadTextFileValue, ResourceClassAndPropertyDefinitions, ResourceClassDefinition, ResourceClassDefinitionWithPropertyDefinition, @@ -505,6 +506,11 @@ export class ResourceComponent implements OnInit, OnChanges, OnDestroy { const archive = new FileRepresentation(fileValue); representations.push(archive); + } else if (resource.res.properties[Constants.HasTextFileValue]) { + + const fileValue: ReadTextFileValue = resource.res.properties[Constants.HasTextFileValue][0] as ReadTextFileValue; + const text = new FileRepresentation(fileValue); + representations.push(text); } return representations; @@ -566,7 +572,8 @@ export class ResourceComponent implements OnInit, OnChanges, OnDestroy { resource.res.properties[Constants.HasDocumentFileValue] || resource.res.properties[Constants.HasAudioFileValue] || resource.res.properties[Constants.HasMovingImageFileValue] || - resource.res.properties[Constants.HasArchiveFileValue]) { + resource.res.properties[Constants.HasArchiveFileValue] || + resource.res.properties[Constants.HasTextFileValue]) { // --> TODO: check if resources is a StillImageRepresentation using the ontology responder (support for subclass relations required) // the resource is a StillImageRepresentation, check if there are regions pointing to it diff --git a/src/assets/style/_elements.scss b/src/assets/style/_elements.scss index 6b9b9ee3eb..40c3803d42 100644 --- a/src/assets/style/_elements.scss +++ b/src/assets/style/_elements.scss @@ -299,7 +299,8 @@ a, &.video, &.audio, - &.archive { + &.archive, + &.text { height: auto; } .caption {