diff --git a/src/app/workspace/resource/representation/still-image/still-image.component.html b/src/app/workspace/resource/representation/still-image/still-image.component.html index d3ba934e4e..889ef6c51c 100644 --- a/src/app/workspace/resource/representation/still-image/still-image.component.html +++ b/src/app/workspace/resource/representation/still-image/still-image.component.html @@ -35,13 +35,19 @@ more_vert - - Open file in new tab - + + + @@ -88,16 +94,12 @@ - + - diff --git a/src/app/workspace/resource/representation/still-image/still-image.component.scss b/src/app/workspace/resource/representation/still-image/still-image.component.scss index 5440e21c6d..553d04767b 100644 --- a/src/app/workspace/resource/representation/still-image/still-image.component.scss +++ b/src/app/workspace/resource/representation/still-image/still-image.component.scss @@ -21,6 +21,7 @@ color: $bright; background-color: $dark; height: calc(100% - 64px); + border-radius: 8px 8px 0px 0px; &.drawing { cursor: crosshair; @@ -110,6 +111,14 @@ z-index: 1000; } +/* + Openseadragon styling + */ + +::ng-deep .openseadragon-container { + border-radius: 8px 8px 0px 0px; +} + /* Overlay styling */ diff --git a/src/app/workspace/resource/representation/still-image/still-image.component.spec.ts b/src/app/workspace/resource/representation/still-image/still-image.component.spec.ts index b70449f174..cc376481dd 100644 --- a/src/app/workspace/resource/representation/still-image/still-image.component.spec.ts +++ b/src/app/workspace/resource/representation/still-image/still-image.component.spec.ts @@ -2,9 +2,9 @@ import { CdkCopyToClipboard } from '@angular/cdk/clipboard'; import { OverlayContainer } from '@angular/cdk/overlay'; import { HarnessLoader } from '@angular/cdk/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; -import { HttpClientModule } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; import { Component, OnInit, ViewChild } from '@angular/core'; -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; @@ -124,7 +124,7 @@ describe('StillImageComponent', () => { let rootLoader: HarnessLoader; let overlayContainer: OverlayContainer; - beforeEach(waitForAsync(() => { + beforeEach(() => { const adminSpyObj = { v2: { @@ -140,7 +140,7 @@ describe('StillImageComponent', () => { ], imports: [ BrowserAnimationsModule, - HttpClientModule, + HttpClientTestingModule, MatDialogModule, MatIconModule, MatMenuModule, @@ -164,7 +164,7 @@ describe('StillImageComponent', () => { ] }) .compileComponents(); - })); + }); beforeEach(() => { testHostFixture = TestBed.createComponent(TestHostComponent); @@ -173,9 +173,6 @@ describe('StillImageComponent', () => { overlayContainer = TestBed.inject(OverlayContainer); rootLoader = TestbedHarnessEnvironment.documentRootLoader(testHostFixture); - }); - - it('should create', () => { expect(testHostComponent).toBeTruthy(); expect(testHostComponent.osdViewerComp).toBeTruthy(); }); diff --git a/src/app/workspace/resource/representation/still-image/still-image.component.ts b/src/app/workspace/resource/representation/still-image/still-image.component.ts index b1d0c1b101..3343afb610 100644 --- a/src/app/workspace/resource/representation/still-image/still-image.component.ts +++ b/src/app/workspace/resource/representation/still-image/still-image.component.ts @@ -14,6 +14,7 @@ import { import { MatDialog, MatDialogConfig } from '@angular/material/dialog'; import { MatIconRegistry } from '@angular/material/icon'; import { DomSanitizer } from '@angular/platform-browser'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; import { ApiResponseError, Constants, @@ -136,6 +137,7 @@ export class StillImageComponent implements OnChanges, OnDestroy, AfterViewInit loading = true; failedToLoad = false; + originalFilename: string; regionDrawMode = false; // stores whether viewer is currently drawing a region private _regionDragInfo; // stores the information of the first click for drawing a region @@ -144,6 +146,7 @@ export class StillImageComponent implements OnChanges, OnDestroy, AfterViewInit constructor( @Inject(DspApiConnectionToken) private _dspApiConnection: KnoraApiConnection, + private readonly _http: HttpClient, private _dialog: MatDialog, private _domSanitizer: DomSanitizer, private _elementRef: ElementRef, @@ -190,6 +193,8 @@ export class StillImageComponent implements OnChanges, OnDestroy, AfterViewInit this._setupViewer(); } if (changes['images']) { + this._getOriginalFilename(); + this._openImages(); this._unhighlightAllRegions(); // --> TODO: check if this is necessary or could be handled below @@ -220,7 +225,7 @@ export class StillImageComponent implements OnChanges, OnDestroy, AfterViewInit /** * renders all ReadStillImageFileValues to be found in [[this.images]]. - * (Although this.images is a Angular Input property, the built-in change detection of Angular does not detect changes in complex objects or arrays, only reassignment of objects/arrays. + * (Although this.images is an Angular Input property, the built-in change detection of Angular does not detect changes in complex objects or arrays, only reassignment of objects/arrays. * Use this method if additional ReadStillImageFileValues were added to this.images after creation/assignment of the this.images array.) */ updateImages() { @@ -232,7 +237,7 @@ export class StillImageComponent implements OnChanges, OnDestroy, AfterViewInit /** * renders all regions to be found in [[this.images]]. - * (Although this.images is a Angular Input property, the built-in change detection of Angular does not detect changes in complex objects or arrays, only reassignment of objects/arrays. + * (Although this.images is an Angular Input property, the built-in change detection of Angular does not detect changes in complex objects or arrays, only reassignment of objects/arrays. * Use this method if additional regions were added to the resources.images) */ updateRegions() { @@ -360,6 +365,32 @@ export class StillImageComponent implements OnChanges, OnDestroy, AfterViewInit this._notification.openSnackBar(message); } + async downloadStillImage(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.HasStillImageFileValue][0].id; @@ -384,11 +415,31 @@ export class StillImageComponent implements OnChanges, OnDestroy, AfterViewInit }); } + openImageInNewTab(url: string) { + window.open(url, '_blank'); + } + openPage(p: number) { this.regionDrawMode = false; this.goToPage.emit(p); } + private _getOriginalFilename() { + const requestOptions = { + headers: new HttpHeaders({ 'Content-Type': 'application/json' }), + withCredentials: true + }; + + const index = this.images[0].fileValue.fileUrl.indexOf(this.images[0].fileValue.filename); + const pathToJson = this.images[0].fileValue.fileUrl.substring(0, index + this.images[0].fileValue.filename.length) + '/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; @@ -403,6 +454,8 @@ export class StillImageComponent implements OnChanges, OnDestroy, AfterViewInit this._valueOperationEventService.emit( new EmitEvent(Events.FileValueUpdated, new UpdatedFileEventValue( res2.properties[Constants.HasStillImageFileValue][0]))); + + this._getOriginalFilename(); }, (error: ApiResponseError) => { this._errorHandler.showMessage(error); @@ -415,6 +468,7 @@ export class StillImageComponent implements OnChanges, OnDestroy, AfterViewInit * @param startPoint the start point of the drawing * @param endPoint the end point of the drawing * @param imageSize the image size for calculations + * @param overlay the overlay element that represents the region */ private _openRegionDialog(startPoint: Point2D, endPoint: Point2D, imageSize: Point2D, overlay: Element): void { const dialogConfig: MatDialogConfig = { @@ -708,7 +762,8 @@ export class StillImageComponent implements OnChanges, OnDestroy, AfterViewInit * @param geometry - the geometry describing the ROI * @param aspectRatio - the aspectRatio (h/w) of the image on which the geometry should be placed * @param xOffset - the x-offset in Openseadragon viewport coordinates of the image on which the geometry should be placed - * @param toolTip - the tooltip which should be displayed on mousehover of the svg element + * @param regionLabel - the label of the region + * @param regionComment - the comment of the region */ private _createSVGOverlay(regionIri: string, geometry: RegionGeometry, aspectRatio: number, xOffset: number, regionLabel: string, regionComment: string): void { const lineColor = geometry.lineColor; diff --git a/src/app/workspace/resource/resource.component.html b/src/app/workspace/resource/resource.component.html index cfd3a1a958..8d088c954d 100644 --- a/src/app/workspace/resource/resource.component.html +++ b/src/app/workspace/resource/resource.component.html @@ -13,7 +13,7 @@ [resourceIri]="incomingResource ? incomingResource.res.id : resource.res.id" [project]="resource.res.attachedToProject" [currentTab]="selectedTabLabel" - [parentResource]="resource.res" + [parentResource]="incomingResource ? incomingResource.res : resource.res" [activateRegion]="selectedRegion" (loaded)="representationLoaded($event)" (goToPage)="compoundNavigation($event)"