@knora/viewer
Version:
Knora ui module: viewer
1,085 lines (1,054 loc) • 92 kB
JavaScript
import { __decorate, __metadata, __param } from 'tslib';
import { Component, EventEmitter, ElementRef, Input, Output, HostListener, Inject, ViewChild, NgModule } from '@angular/core';
import { Constants, Point2D, ReadBooleanValue, ReadColorValue, KnoraPeriod, Precision, ReadDateValue, ReadDecimalValue, ReadGeomValue, ReadIntValue, ReadIntervalValue, ReadLinkValue, ReadListValue, ReadTextValueAsHtml, ReadTextValueAsString, ReadTextValueAsXml, ReadFileValue, ReadUriValue, ResourcePropertyDefinition, KnoraApiConnection } from '@knora/api';
import { OntologyInformation, KnoraApiConnectionToken, SearchParamsService, KuiCoreModule } from '@knora/core';
import { Router, ActivatedRoute } from '@angular/router';
import { PageEvent, MatMenuModule } from '@angular/material';
import { CommonModule } from '@angular/common';
import { FlexLayoutModule } from '@angular/flex-layout';
import { ReactiveFormsModule } from '@angular/forms';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatNativeDateModule } from '@angular/material/core';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatListModule } from '@angular/material/list';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { MatTabsModule } from '@angular/material/tabs';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatTooltipModule } from '@angular/material/tooltip';
import { KuiActionModule } from '@knora/action';
let MovingImageComponent = class MovingImageComponent {
constructor() { }
ngOnInit() {
}
};
MovingImageComponent = __decorate([
Component({
selector: 'kui-moving-image',
template: "<!-- video container -->\n<div class=\"moving-image-viewer\">\n\n <!-- video source -->\n <video></video>\n\n <!-- timeline incl. preview -->\n <div class=\"kui-mi-timeline\">\n\n </div>\n <div class=\"kui-mi-navigation\">\n\n\n </div>\n\n</div>\n",
styles: [""]
}),
__metadata("design:paramtypes", [])
], MovingImageComponent);
var StillImageComponent_1;
/**
* Represents a region.
* Contains a reference to the resource representing the region and its geometries.
*/
class ImageRegion {
/**
*
* @param regionResource a resource of type Region
*/
constructor(regionResource) {
this.regionResource = regionResource;
}
/**
* Get all geometry information belonging to this region.
*
* @returns
*/
getGeometries() {
return this.regionResource.properties[Constants.HasGeometry];
}
}
/**
* Represents an image including its regions.
*/
class StillImageRepresentation {
/**
*
* @param stillImageFileValue a [[ReadStillImageFileValue]] representing an image.
* @param regions the regions belonging to the image.
*/
constructor(stillImageFileValue, regions) {
this.stillImageFileValue = stillImageFileValue;
this.regions = regions;
}
}
/**
* Represents a geometry belonging to a specific region.
*/
class GeometryForRegion {
/**
*
* @param geometry the geometrical information.
* @param region the region the geometry belongs to.
*/
constructor(geometry, region) {
this.geometry = geometry;
this.region = region;
}
}
/**
* This component creates a OpenSeadragon viewer instance.
* Accepts an array of ReadResource containing (among other resources) ReadStillImageFileValues to be rendered.
* @member resources - resources containing (among other resources) the StillImageFileValues and incoming regions to be rendered. (Use as angular @Input data binding property.)
*/
let StillImageComponent = StillImageComponent_1 = class StillImageComponent {
constructor(elementRef) {
this.elementRef = elementRef;
this.currentImageIndex = new EventEmitter();
this.regionHovered = new EventEmitter();
this.regions = {};
}
/**
* Calculates the surface of a rectangular region.
*
* @param geom the region's geometry.
* @returns the surface.
*/
static surfaceOfRectangularRegion(geom) {
if (geom.type !== 'rectangle') {
console.log('expected rectangular region, but ' + geom.type + ' given');
return 0;
}
const w = Math.max(geom.points[0].x, geom.points[1].x) - Math.min(geom.points[0].x, geom.points[1].x);
const h = Math.max(geom.points[0].y, geom.points[1].y) - Math.min(geom.points[0].y, geom.points[1].y);
return w * h;
}
/**
* Prepare tile sources from the given sequence of [[ReadStillImageFileValue]].
*
* @param imagesToDisplay the given file values to de displayed.
* @returns the tile sources to be passed to OSD viewer.
*/
static prepareTileSourcesFromFileValues(imagesToDisplay) {
let imageXOffset = 0;
const imageYOffset = 0;
const tileSources = [];
for (const image of imagesToDisplay) {
const sipiBasePath = image.iiifBaseUrl + '/' + image.filename;
const width = image.dimX;
const height = image.dimY;
// construct OpenSeadragon tileSources according to https://openseadragon.github.io/docs/OpenSeadragon.Viewer.html#open
tileSources.push({
// construct IIIF tileSource configuration according to
// http://iiif.io/api/image/2.1/#technical-properties
// see also http://iiif.io/api/image/2.0/#a-implementation-notes
'tileSource': {
'@context': 'http://iiif.io/api/image/2/context.json',
'@id': sipiBasePath,
'height': height,
'width': width,
'profile': ['http://iiif.io/api/image/2/level2.json'],
'protocol': 'http://iiif.io/api/image',
'tiles': [{
'scaleFactors': [1, 2, 4, 8, 16, 32],
'width': 1024
}]
},
'x': imageXOffset,
'y': imageYOffset
});
imageXOffset++;
}
return tileSources;
}
ngOnChanges(changes) {
if (changes['images'] && changes['images'].isFirstChange()) {
this.setupViewer();
// this.currentImageIri.emit(this.images[this.viewer.currentPage()].stillImageFileValue.id);
}
if (changes['images']) {
this.openImages();
this.renderRegions();
this.unhighlightAllRegions();
if (this.activateRegion !== undefined) {
this.highlightRegion(this.activateRegion);
}
}
else if (changes['activateRegion']) {
this.unhighlightAllRegions();
if (this.activateRegion !== undefined) {
this.highlightRegion(this.activateRegion);
}
}
if (this.viewer) {
// console.log(this.viewer);
// this.currentImageIndex.emit(this.viewer.currentPage());
}
}
ngOnInit() {
// initialisation is done on first run of ngOnChanges
}
ngOnDestroy() {
if (this.viewer) {
this.viewer.destroy();
this.viewer = undefined;
}
}
/**
* 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.
* Use this method if additional ReadStillImageFileValues were added to this.images after creation/assignment of the this.images array.)
*/
updateImages() {
if (!this.viewer) {
this.setupViewer();
}
this.openImages();
}
/**
* 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.
* Use this method if additional regions were added to the resources.images)
*/
updateRegions() {
if (!this.viewer) {
this.setupViewer();
}
this.renderRegions();
}
/**
* Highlights the polygon elements associated with the given region.
*
* @param regionIri the Iri of the region whose polygon elements should be highlighted..
*/
highlightRegion(regionIri) {
const activeRegion = this.regions[regionIri];
if (activeRegion !== undefined) {
for (const pol of activeRegion) {
pol.setAttribute('class', 'roi-svgoverlay active');
}
}
}
/**
* Unhighlights the polygon elements of all regions.
*
*/
unhighlightAllRegions() {
for (const reg in this.regions) {
if (this.regions.hasOwnProperty(reg)) {
for (const pol of this.regions[reg]) {
pol.setAttribute('class', 'roi-svgoverlay');
}
}
}
}
/**
* Initializes the OpenSeadragon viewer
*/
setupViewer() {
const viewerContainer = this.elementRef.nativeElement.getElementsByClassName('osd-container')[0];
const osdOptions = {
element: viewerContainer,
sequenceMode: true,
showReferenceStrip: true,
showNavigator: true,
zoomInButton: 'KUI_OSD_ZOOM_IN',
zoomOutButton: 'KUI_OSD_ZOOM_OUT',
previousButton: 'KUI_OSD_PREV_PAGE',
nextButton: 'KUI_OSD_NEXT_PAGE',
homeButton: 'KUI_OSD_HOME',
fullPageButton: 'KUI_OSD_FULL_PAGE',
rotateLeftButton: 'KUI_OSD_ROTATE_LEFT',
rotateRightButton: 'KUI_OSD_ROTATE_RIGHT' // doesn't work yet
};
this.viewer = new OpenSeadragon.Viewer(osdOptions);
this.viewer.addHandler('full-screen', function (args) {
if (args.fullScreen) {
viewerContainer.classList.add('fullscreen');
}
else {
viewerContainer.classList.remove('fullscreen');
}
});
this.viewer.addHandler('resize', function (args) {
args.eventSource.svgOverlay().resize();
});
const fileValues = this.images.map((img) => {
return img;
});
this.viewer.addHandler('page', function (event) {
console.log('event on page', event);
console.log('Now on page', event.page);
const index = event.page;
console.log('= id', fileValues[index].id);
const id = fileValues[index].id;
// return id;
});
//
// this.currentImageIri.emit(this.viewer.getCurrentImage());
}
/**
* Adds all images in this.images to the viewer.
* Images are positioned in a horizontal row next to each other.
*/
openImages() {
// imageXOffset controls the x coordinate of the left side of each image in the OpenSeadragon viewport coordinate system.
// The first image has its left side at x = 0, and all images are scaled to have a width of 1 in viewport coordinates.
// see also: https://openseadragon.github.io/examples/viewport-coordinates/
const fileValues = this.images.map((img) => {
return img;
});
// display only the defined range of this.images
const tileSources = StillImageComponent_1.prepareTileSourcesFromFileValues(fileValues);
this.removeOverlays();
this.viewer.open(tileSources);
}
/**
* Removes SVG overlays from the DOM.
*/
removeOverlays() {
for (const reg in this.regions) {
if (this.regions.hasOwnProperty(reg)) {
for (const pol of this.regions[reg]) {
if (pol instanceof SVGPolygonElement) {
pol.remove();
}
}
}
}
this.regions = {};
// TODO: make this work by using osdviewer's addOverlay method
this.viewer.clearOverlays();
}
/**
* Adds a ROI-overlay to the viewer for every region of every image in this.images
*/
renderRegions() {
this.removeOverlays();
let imageXOffset = 0; // see documentation in this.openImages() for the usage of imageXOffset
for (const image of this.images) {
const aspectRatio = (image.dimY / image.dimX);
// collect all geometries belonging to this page
const geometries = [];
/* TODO: knora-api-js-lib integration needs another region handling?
image.regions.map((reg) => {
this.regions[reg.regionResource.id] = [];
const geoms = reg.getGeometries();
geoms.map((geom) => {
const geomForReg = new GeometryForRegion(geom.geometry, reg.regionResource);
geometries.push(geomForReg);
});
});
// sort all geometries belonging to this page
geometries.sort((geom1, geom2) => {
if (geom1.geometry.type === 'rectangle' && geom2.geometry.type === 'rectangle') {
const surf1 = StillImageComponent.surfaceOfRectangularRegion(geom1.geometry);
const surf2 = StillImageComponent.surfaceOfRectangularRegion(geom2.geometry);
// if reg1 is smaller than reg2, return 1
// reg1 then comes after reg2 and thus is rendered later
if (surf1 < surf2) {
return 1;
} else {
return -1;
}
} else {
return 0;
}
});
// render all geometries for this page
for (const geom of geometries) {
const geometry = geom.geometry;
this.createSVGOverlay(geom.region.id, geometry, aspectRatio, imageXOffset, geom.region.label);
}
*/
imageXOffset++;
}
}
/**
* Creates and adds a ROI-overlay to the viewer
* @param regionIri the Iri of the region.
* @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
*/
createSVGOverlay(regionIri, geometry, aspectRatio, xOffset, toolTip) {
const lineColor = geometry.lineColor;
const lineWidth = geometry.lineWidth;
let svgElement;
switch (geometry.type) {
case 'rectangle':
svgElement = document.createElementNS('http://www.w3.org/2000/svg', 'polygon'); // yes, we render rectangles as svg polygon elements
this.addSVGAttributesRectangle(svgElement, geometry, aspectRatio, xOffset);
break;
case 'polygon':
svgElement = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
this.addSVGAttributesPolygon(svgElement, geometry, aspectRatio, xOffset);
break;
case 'circle':
svgElement = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
this.addSVGAttributesCircle(svgElement, geometry, aspectRatio, xOffset);
break;
default:
console.log('ERROR: StillImageOSDViewerComponent.createSVGOverlay: unknown geometryType: ' + geometry.type);
return;
}
svgElement.id = 'roi-svgoverlay-' + Math.random() * 10000;
svgElement.setAttribute('class', 'roi-svgoverlay');
svgElement.setAttribute('style', 'stroke: ' + lineColor + '; stroke-width: ' + lineWidth + 'px;');
// event when a region is clicked (output)
svgElement.addEventListener('click', () => {
this.regionHovered.emit(regionIri);
}, false);
const svgTitle = document.createElementNS('http://www.w3.org/2000/svg', 'title');
svgTitle.textContent = toolTip;
const svgGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g');
svgGroup.appendChild(svgTitle);
svgGroup.appendChild(svgElement);
const overlay = this.viewer.svgOverlay();
overlay.node().appendChild(svgGroup); // TODO: use method osdviewer's method addOverlay
this.regions[regionIri].push(svgElement);
}
/**
* Adds the necessary attributes to create a ROI-overlay of type 'rectangle' to a SVGElement
* @param svgElement - an SVGElement (should have type 'polygon' (sic))
* @param geometry - the geometry describing the rectangle
* @param aspectRatio - the aspectRatio (h/w) of the image on which the circle should be placed
* @param xOffset - the x-offset in Openseadragon viewport coordinates of the image on which the circle should be placed
*/
addSVGAttributesRectangle(svgElement, geometry, aspectRatio, xOffset) {
const pointA = geometry.points[0];
const pointB = geometry.points[1];
// geometry.points contains two diagonally opposed corners of the rectangle, but the order of the corners is arbitrary.
// We therefore construct the upperleft (UL), lowerright (LR), upperright (UR) and lowerleft (LL) positions of the corners with min and max operations.
const positionUL = new Point2D(Math.min(pointA.x, pointB.x), Math.min(pointA.y, pointB.y));
const positionLR = new Point2D(Math.max(pointA.x, pointB.x), Math.max(pointA.y, pointB.y));
const positionUR = new Point2D(Math.max(pointA.x, pointB.x), Math.min(pointA.y, pointB.y));
const positionLL = new Point2D(Math.min(pointA.x, pointB.x), Math.max(pointA.y, pointB.y));
const points = [positionUL, positionUR, positionLR, positionLL];
const viewCoordPoints = this.image2ViewPortCoords(points, aspectRatio, xOffset);
const pointsString = this.createSVGPolygonPointsAttribute(viewCoordPoints);
svgElement.setAttribute('points', pointsString);
}
/**
* Adds the necessary attributes to create a ROI-overlay of type 'polygon' to a SVGElement
* @param svgElement - an SVGElement (should have type 'polygon')
* @param geometry - the geometry describing the polygon
* @param aspectRatio - the aspectRatio (h/w) of the image on which the circle should be placed
* @param xOffset - the x-offset in Openseadragon viewport coordinates of the image on which the circle should be placed
*/
addSVGAttributesPolygon(svgElement, geometry, aspectRatio, xOffset) {
const viewCoordPoints = this.image2ViewPortCoords(geometry.points, aspectRatio, xOffset);
const pointsString = this.createSVGPolygonPointsAttribute(viewCoordPoints);
svgElement.setAttribute('points', pointsString);
}
/**
* Adds the necessary attributes to create a ROI-overlay of type 'circle' to a SVGElement
* @param svgElement - an SVGElement (should have type 'circle')
* @param geometry - the geometry describing the circle
* @param aspectRatio - the aspectRatio (h/w) of the image on which the circle should be placed
* @param xOffset - the x-offset in Openseadragon viewport coordinates of the image on which the circle should be placed
*/
addSVGAttributesCircle(svgElement, geometry, aspectRatio, xOffset) {
const viewCoordPoints = this.image2ViewPortCoords(geometry.points, aspectRatio, xOffset);
const cx = String(viewCoordPoints[0].x);
const cy = String(viewCoordPoints[0].y);
// geometry.radius contains not the radius itself, but the coordinates of a (arbitrary) point on the circle.
// We therefore have to calculate the length of the vector geometry.radius to get the actual radius. -> sqrt(x^2 + y^2)
// Since geometry.radius has its y coordinate scaled to the height of the image,
// we need to multiply it with the aspectRatio to get to the scale used by Openseadragon, analoguous to this.image2ViewPortCoords()
const radius = String(Math.sqrt(geometry.radius.x * geometry.radius.x + aspectRatio * aspectRatio * geometry.radius.y * geometry.radius.y));
svgElement.setAttribute('cx', cx);
svgElement.setAttribute('cy', cy);
svgElement.setAttribute('r', radius);
}
/**
* Maps a Point2D[] with coordinates relative to an image to a new Point2D[] with coordinates in the viewport coordinate system of Openseadragon
* see also: https://openseadragon.github.io/examples/viewport-coordinates/
* @param points - an array of points in coordinate system relative to an image
* @param aspectRatio - the aspectRatio (h/w) of the image
* @param xOffset - the x-offset in viewport coordinates of the image
* @returns - a new Point2D[] with coordinates in the viewport coordinate system of Openseadragon
*/
image2ViewPortCoords(points, aspectRatio, xOffset) {
return points.map((point) => {
return new Point2D(point.x + xOffset, point.y * aspectRatio);
});
}
/**
* Returns a string in the format expected by the 'points' attribute of a SVGElement
* @param points - an array of points to be serialized to a string
* @returns - the points serialized to a string in the format expected by the 'points' attribute of a SVGElement
*/
createSVGPolygonPointsAttribute(points) {
let pointsString = '';
for (const i in points) {
if (points.hasOwnProperty(i)) {
pointsString += points[i].x;
pointsString += ',';
pointsString += points[i].y;
pointsString += ' ';
}
}
return pointsString;
}
getCurrentImage() {
}
};
StillImageComponent.ctorParameters = () => [
{ type: ElementRef }
];
__decorate([
Input(),
__metadata("design:type", Array)
], StillImageComponent.prototype, "images", void 0);
__decorate([
Input(),
__metadata("design:type", String)
], StillImageComponent.prototype, "imageCaption", void 0);
__decorate([
Input(),
__metadata("design:type", String)
], StillImageComponent.prototype, "activateRegion", void 0);
__decorate([
Output(),
__metadata("design:type", EventEmitter)
], StillImageComponent.prototype, "currentImageIndex", void 0);
__decorate([
Output(),
__metadata("design:type", Object)
], StillImageComponent.prototype, "regionHovered", void 0);
StillImageComponent = StillImageComponent_1 = __decorate([
Component({
selector: 'kui-still-image',
template: "<div class=\"still-image-viewer\">\n <div class=\"navigation left\">\n <button mat-button class=\"full-size\" id=\"KUI_OSD_PREV_PAGE\">\n <mat-icon>keyboard_arrow_left</mat-icon>\n </button>\n </div>\n\n <!-- main content with navigation and osd viewer -->\n <div class=\"content\">\n\n <!-- openseadragon (osd) viewer -->\n <div class=\"osd-container\"></div>\n <!-- /openseadragon (osd) -->\n\n <!-- footer with image caption e.g. copyright information -->\n <div class=\"footer\">\n <p class=\"mat-caption\" [innerHtml]=\"imageCaption\"></p>\n </div>\n\n <!-- action panel with tools for image -->\n <mat-toolbar class=\"action\">\n <mat-toolbar-row>\n <!-- home button -->\n <span>\n <button mat-icon-button id=\"KUI_OSD_HOME\">\n <mat-icon>home</mat-icon>\n </button>\n </span>\n <!-- zoom buttons -->\n <span class=\"fill-remaining-space\"></span>\n <span>\n <button mat-icon-button id=\"KUI_OSD_ZOOM_IN\">\n <mat-icon>add</mat-icon>\n </button>\n <button mat-icon-button id=\"KUI_OSD_ZOOM_OUT\">\n <mat-icon>remove</mat-icon>\n </button>\n </span>\n <!-- window button -->\n <span class=\"fill-remaining-space\"></span>\n <span>\n <button mat-icon-button id=\"KUI_OSD_FULL_PAGE\">\n <mat-icon>fullscreen</mat-icon>\n </button>\n </span>\n </mat-toolbar-row>\n </mat-toolbar>\n\n </div>\n\n <div class=\"navigation\">\n <button mat-button class=\"full-size\" id=\"KUI_OSD_NEXT_PAGE\" (click)=\"getCurrentImage()\">\n <mat-icon>keyboard_arrow_right</mat-icon>\n </button>\n </div>\n\n</div>\n\n<!-- simple image viewer e.g. as a preview -->\n<!-- TODO: handle images array -->\n<!--<img *ngIf=\"simple && images?.length === 1; else osdViewer\" [src]=\"simpleImageExample\">-->\n\n\n<!--\n <div>\n <span *ngIf=\"images.length > 1\" (click)=\"gotoLeft()\"><<</span>\n <span *ngIf=\"images.length > 1\" (click)=\"gotoRight()\">>></span>\n </div>\n-->\n",
styles: [".still-image-viewer{display:-webkit-inline-box;display:inline-flex;height:400px;max-width:960px;width:100%}@media (max-height:636px){.still-image-viewer{height:300px}}.still-image-viewer .navigation{height:calc(400px + 64px + 24px);width:36px}.still-image-viewer .navigation .mat-button.full-size{height:100%!important;width:36px!important;padding:0!important;min-width:36px!important}.still-image-viewer .content{height:calc(400px + 64px + 24px);max-width:calc(960px - (2 * 36px));width:calc(100% - (2 * 36px))}.still-image-viewer .content .osd-container{color:#ccc;background-color:#000;height:400px}.still-image-viewer .content .osd-container.fullscreen{max-width:100vw}.still-image-viewer .content .footer p{color:#ccc;background-color:#000;height:24px;margin:0;padding:0 16px}::ng-deep .roi-svgoverlay{opacity:.4;fill:transparent;stroke:#00695c;stroke-width:2px;vector-effect:non-scaling-stroke}.roi-svgoverlay:focus,::ng-deep .roi-svgoverlay:hover{opacity:1}::ng-deep .roi-svgoverlay.active{opacity:1}"]
}),
__metadata("design:paramtypes", [ElementRef])
], StillImageComponent);
let BooleanValueComponent = class BooleanValueComponent {
constructor() { }
set valueObject(value) {
this._booleanValueObj = value;
}
get valueObject() {
return this._booleanValueObj;
}
};
__decorate([
Input(),
__metadata("design:type", ReadBooleanValue),
__metadata("design:paramtypes", [ReadBooleanValue])
], BooleanValueComponent.prototype, "valueObject", null);
BooleanValueComponent = __decorate([
Component({
selector: 'kui-boolean-value',
template: "<mat-checkbox [checked]=\"valueObject.bool\" readonly=\"true\"></mat-checkbox>\n",
styles: [".mat-form-field{width:320px}.fill-remaining-space{-webkit-box-flex:1;flex:1 1 auto}.center{text-align:center}a{text-decoration:none;color:inherit}.kui-link{cursor:pointer;border-bottom:2px solid rgba(0,105,92,.25)}.lv-prop-label{color:rgba(0,0,0,.54)}.lv-html-text{position:relative;overflow:hidden}"]
}),
__metadata("design:paramtypes", [])
], BooleanValueComponent);
let ColorValueComponent = class ColorValueComponent {
constructor() {
}
set valueObject(value) {
this._colorValueObj = value;
}
get valueObject() {
return this._colorValueObj;
}
};
__decorate([
Input(),
__metadata("design:type", ReadColorValue),
__metadata("design:paramtypes", [ReadColorValue])
], ColorValueComponent.prototype, "valueObject", null);
ColorValueComponent = __decorate([
Component({
selector: 'kui-color-value',
template: "<span [style.background-color]=\"valueObject.color\">{{valueObject.color}}</span>\n",
styles: [".fill-remaining-space{-webkit-box-flex:1;flex:1 1 auto}.center{text-align:center}a{text-decoration:none;color:inherit}.kui-link{cursor:pointer;border-bottom:2px solid rgba(0,105,92,.25)}.lv-prop-label{color:rgba(0,0,0,.54)}.lv-html-text{position:relative;overflow:hidden}.mat-form-field{width:36px;overflow-x:visible}"]
}),
__metadata("design:paramtypes", [])
], ColorValueComponent);
let DateValueComponent = class DateValueComponent {
constructor() { }
set calendar(value) {
this._calendar = value;
}
get calendar() {
return this._calendar;
}
set era(value) {
this._era = value;
}
get era() {
return this._era;
}
set valueObject(value) {
this._dateValueObj = value;
const dateOrRange = this.valueObject.date;
if (dateOrRange instanceof KnoraPeriod) {
// period (start and end dates)
this.period = true;
this.dates = [this.getJSDate(dateOrRange.start), this.getJSDate(dateOrRange.end)];
}
else {
// single date
this.period = false;
this.dates = [this.getJSDate(dateOrRange)];
}
}
get valueObject() {
return this._dateValueObj;
}
/**
* Converts a `KnoraDate` to a JS Date, providing necessary formatting information.
* JULIAN and GREGORIAN calendar are the only available for the moment.
*
* @param date the date to be converted.
* @return DateFormatter.
*/
getJSDate(date) {
if (date.precision === Precision.yearPrecision) {
return {
format: 'yyyy',
date: new Date(date.year.toString()),
era: date.era,
calendar: date.calendar
};
}
else if (date.precision === Precision.monthPrecision) {
return {
format: 'MMMM ' + 'yyyy',
date: new Date(date.year, date.month - 1, 1),
era: date.era,
calendar: date.calendar
};
}
else if (date.precision === Precision.dayPrecision) {
return {
format: 'longDate',
date: new Date(date.year, date.month - 1, date.day),
era: date.era,
calendar: date.calendar
};
}
else {
console.error('Error: incorrect precision for date');
}
}
};
__decorate([
Input(),
__metadata("design:type", Boolean),
__metadata("design:paramtypes", [Boolean])
], DateValueComponent.prototype, "calendar", null);
__decorate([
Input(),
__metadata("design:type", Boolean),
__metadata("design:paramtypes", [Boolean])
], DateValueComponent.prototype, "era", null);
__decorate([
Input(),
__metadata("design:type", ReadDateValue),
__metadata("design:paramtypes", [ReadDateValue])
], DateValueComponent.prototype, "valueObject", null);
DateValueComponent = __decorate([
Component({
selector: 'kui-date-value',
template: "<span *ngIf=\"period; else preciseDate\">\n {{dates[0].date | date: dates[0].format}}\n <span *ngIf=\"era\">\n {{dates[0].era}}\n </span>\n - {{dates[1].date | date: dates[1].format}}\n <span *ngIf=\"era\">\n {{dates[1].era}}\n </span>\n\n <span *ngIf=\"calendar\">\n ({{dates[0].calendar}})\n </span>\n</span>\n\n<ng-template #preciseDate>\n\n <span>\n {{dates[0].date | date: dates[0].format}}\n <span *ngIf=\"era\">\n {{dates[0].era}}\n </span>\n <span *ngIf=\"calendar\">\n ({{dates[0].calendar}})\n </span>\n </span>\n\n</ng-template>\n",
styles: [".mat-form-field{width:320px}.fill-remaining-space{-webkit-box-flex:1;flex:1 1 auto}.center{text-align:center}a{text-decoration:none;color:inherit}.kui-link{cursor:pointer;border-bottom:2px solid rgba(0,105,92,.25)}.lv-prop-label{color:rgba(0,0,0,.54)}.lv-html-text{position:relative;overflow:hidden}"]
}),
__metadata("design:paramtypes", [])
], DateValueComponent);
let DecimalValueComponent = class DecimalValueComponent {
constructor() { }
set valueObject(value) {
this._decimalValueObj = value;
}
get valueObject() {
return this._decimalValueObj;
}
};
__decorate([
Input(),
__metadata("design:type", ReadDecimalValue),
__metadata("design:paramtypes", [ReadDecimalValue])
], DecimalValueComponent.prototype, "valueObject", null);
DecimalValueComponent = __decorate([
Component({
selector: 'kui-decimal-value',
template: "<span>{{valueObject.decimal}}</span>",
styles: [".mat-form-field{width:320px}.fill-remaining-space{-webkit-box-flex:1;flex:1 1 auto}.center{text-align:center}a{text-decoration:none;color:inherit}.kui-link{cursor:pointer;border-bottom:2px solid rgba(0,105,92,.25)}.lv-prop-label{color:rgba(0,0,0,.54)}.lv-html-text{position:relative;overflow:hidden}"]
}),
__metadata("design:paramtypes", [])
], DecimalValueComponent);
let GeometryValueComponent = class GeometryValueComponent {
constructor() { }
set valueObject(value) {
this._geomValueObj = value;
}
get valueObject() {
return this._geomValueObj;
}
};
__decorate([
Input(),
__metadata("design:type", ReadGeomValue),
__metadata("design:paramtypes", [ReadGeomValue])
], GeometryValueComponent.prototype, "valueObject", null);
GeometryValueComponent = __decorate([
Component({
selector: 'kui-geometry-value',
template: "<span>{{valueObject.geometry}}</span>\n",
styles: [".mat-form-field{width:320px}.fill-remaining-space{-webkit-box-flex:1;flex:1 1 auto}.center{text-align:center}a{text-decoration:none;color:inherit}.kui-link{cursor:pointer;border-bottom:2px solid rgba(0,105,92,.25)}.lv-prop-label{color:rgba(0,0,0,.54)}.lv-html-text{position:relative;overflow:hidden}"]
}),
__metadata("design:paramtypes", [])
], GeometryValueComponent);
let GeonameValueComponent = class GeonameValueComponent {
constructor() { }
ngOnInit() {
}
};
GeonameValueComponent = __decorate([
Component({
selector: 'kui-geoname-value',
template: "<p>\n geoname-value works!\n</p>",
styles: [".mat-form-field{width:320px}.fill-remaining-space{-webkit-box-flex:1;flex:1 1 auto}.center{text-align:center}a{text-decoration:none;color:inherit}.kui-link{cursor:pointer;border-bottom:2px solid rgba(0,105,92,.25)}.lv-prop-label{color:rgba(0,0,0,.54)}.lv-html-text{position:relative;overflow:hidden}"]
}),
__metadata("design:paramtypes", [])
], GeonameValueComponent);
let IntegerValueComponent = class IntegerValueComponent {
constructor() {
}
set valueObject(value) {
this._integerValueObj = value;
}
get valueObject() {
return this._integerValueObj;
}
};
__decorate([
Input(),
__metadata("design:type", ReadIntValue),
__metadata("design:paramtypes", [ReadIntValue])
], IntegerValueComponent.prototype, "valueObject", null);
IntegerValueComponent = __decorate([
Component({
selector: 'kui-integer-value',
template: "<span>{{valueObject.int}}</span>\n",
styles: [".mat-form-field{width:320px}.fill-remaining-space{-webkit-box-flex:1;flex:1 1 auto}.center{text-align:center}a{text-decoration:none;color:inherit}.kui-link{cursor:pointer;border-bottom:2px solid rgba(0,105,92,.25)}.lv-prop-label{color:rgba(0,0,0,.54)}.lv-html-text{position:relative;overflow:hidden}"]
}),
__metadata("design:paramtypes", [])
], IntegerValueComponent);
let IntervalValueComponent = class IntervalValueComponent {
constructor() { }
set valueObject(value) {
this._intervalValueObj = value;
}
get valueObject() {
return this._intervalValueObj;
}
};
__decorate([
Input(),
__metadata("design:type", ReadIntervalValue),
__metadata("design:paramtypes", [ReadIntervalValue])
], IntervalValueComponent.prototype, "valueObject", null);
IntervalValueComponent = __decorate([
Component({
selector: 'kui-interval-value',
template: "<span>{{valueObject.start}} - {{valueObject.end}}</span>\n",
styles: [".mat-form-field{width:320px}.fill-remaining-space{-webkit-box-flex:1;flex:1 1 auto}.center{text-align:center}a{text-decoration:none;color:inherit}.kui-link{cursor:pointer;border-bottom:2px solid rgba(0,105,92,.25)}.lv-prop-label{color:rgba(0,0,0,.54)}.lv-html-text{position:relative;overflow:hidden}"]
}),
__metadata("design:paramtypes", [])
], IntervalValueComponent);
let LinkValueComponent = class LinkValueComponent {
constructor() {
this.referredResourceClicked = new EventEmitter();
}
set valueObject(value) {
this._linkValueObj = value;
if (this.valueObject.linkedResource !== undefined) {
this.referredResource = this.valueObject.linkedResource.label;
}
else {
this.referredResource = this.valueObject.linkedResourceIri;
}
}
get valueObject() {
return this._linkValueObj;
}
refResClicked() {
this.referredResourceClicked.emit(this._linkValueObj);
}
};
__decorate([
Input(),
__metadata("design:type", ReadLinkValue),
__metadata("design:paramtypes", [ReadLinkValue])
], LinkValueComponent.prototype, "valueObject", null);
__decorate([
Output(),
__metadata("design:type", EventEmitter)
], LinkValueComponent.prototype, "referredResourceClicked", void 0);
LinkValueComponent = __decorate([
Component({
selector: 'kui-link-value',
template: "<a class=\"kui-link\" (click)=\"refResClicked()\">{{referredResource}}</a>\n",
styles: [".mat-form-field{width:320px}.fill-remaining-space{-webkit-box-flex:1;flex:1 1 auto}.center{text-align:center}a{text-decoration:none;color:inherit}.kui-link{cursor:pointer;border-bottom:2px solid rgba(0,105,92,.25)}.lv-prop-label{color:rgba(0,0,0,.54)}.lv-html-text{position:relative;overflow:hidden}"]
}),
__metadata("design:paramtypes", [])
], LinkValueComponent);
let ListValueComponent = class ListValueComponent {
constructor() { }
set valueObject(value) {
this._listValueObj = value;
}
get valueObject() {
return this._listValueObj;
}
};
__decorate([
Input(),
__metadata("design:type", ReadListValue),
__metadata("design:paramtypes", [ReadListValue])
], ListValueComponent.prototype, "valueObject", null);
ListValueComponent = __decorate([
Component({
selector: 'kui-list-value',
template: "<span>{{valueObject.listNodeLabel}}</span>\n",
styles: [".mat-form-field{width:320px}.fill-remaining-space{-webkit-box-flex:1;flex:1 1 auto}.center{text-align:center}a{text-decoration:none;color:inherit}.kui-link{cursor:pointer;border-bottom:2px solid rgba(0,105,92,.25)}.lv-prop-label{color:rgba(0,0,0,.54)}.lv-html-text{position:relative;overflow:hidden}"]
}),
__metadata("design:paramtypes", [])
], ListValueComponent);
let TextValueAsHtmlComponent = class TextValueAsHtmlComponent {
constructor(el) {
this.el = el;
this.referredResourceClicked = new EventEmitter();
}
set ontologyInfo(value) {
this._ontoInfo = value;
}
get ontologyInfo() {
return this._ontoInfo;
}
set bindEvents(value) {
this._bindEvents = value;
}
get bindEvents() {
return this._bindEvents;
}
set valueObject(value) {
this._htmlValueObj = value;
if (this.el.nativeElement.innerHTML) {
this.el.nativeElement.innerHTML = this.valueObject.html;
}
}
get valueObject() {
return this._htmlValueObj;
}
refResClicked(refResourceIri) {
this.referredResourceClicked.emit(refResourceIri);
}
/**
* Binds a click event to standoff links that shows the referred resource.
*
* @param targetElement
*/
onClick(targetElement) {
if (this._bindEvents && targetElement.nodeName.toLowerCase() === 'a'
&& targetElement.className.toLowerCase().indexOf('salsah-link') >= 0
&& targetElement.href !== undefined) {
this.refResClicked(targetElement.href);
// prevent propagation
return false;
}
else if (this.bindEvents && targetElement.nodeName.toLowerCase() === 'a' && targetElement.href !== undefined) {
// open link in a new window
window.open(targetElement.href, '_blank');
// prevent propagation
return false;
}
else {
// prevent propagation
return false;
}
}
};
TextValueAsHtmlComponent.ctorParameters = () => [
{ type: ElementRef }
];
__decorate([
Output(),
__metadata("design:type", EventEmitter)
], TextValueAsHtmlComponent.prototype, "referredResourceClicked", void 0);
__decorate([
Input(),
__metadata("design:type", Object),
__metadata("design:paramtypes", [Object])
], TextValueAsHtmlComponent.prototype, "ontologyInfo", null);
__decorate([
Input(),
__metadata("design:type", Boolean),
__metadata("design:paramtypes", [Boolean])
], TextValueAsHtmlComponent.prototype, "bindEvents", null);
__decorate([
Input(),
__metadata("design:type", ReadTextValueAsHtml),
__metadata("design:paramtypes", [ReadTextValueAsHtml])
], TextValueAsHtmlComponent.prototype, "valueObject", null);
__decorate([
HostListener('click', ['$event.target']),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", void 0)
], TextValueAsHtmlComponent.prototype, "onClick", null);
TextValueAsHtmlComponent = __decorate([
Component({
selector: 'kui-text-value-as-html',
template: "<div>{{valueObject.html}}</div>",
styles: [""]
}),
__metadata("design:paramtypes", [ElementRef])
], TextValueAsHtmlComponent);
let TextValueAsStringComponent = class TextValueAsStringComponent {
constructor() {
this.regexUrl = /(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/;
}
set valueObject(value) {
// console.log(value);
const str = value.text;
if (this.regexUrl.exec(str)) {
const url = this.regexUrl.exec(str)[0];
const newStr = str.replace(this.regexUrl, '<a class="kui-link" href="' + url + '">' + url + '</a>');
value.text = newStr;
this._textStringValueObj = value;
}
else {
this._textStringValueObj = value;
}
}
get valueObject() {
return this._textStringValueObj;
}
};
__decorate([
Input(),
__metadata("design:type", ReadTextValueAsString),
__metadata("design:paramtypes", [ReadTextValueAsString])
], TextValueAsStringComponent.prototype, "valueObject", null);
TextValueAsStringComponent = __decorate([
Component({
selector: 'kui-text-value-as-string',
template: "<span [innerHTML]=\"valueObject.text\"></span>\n",
styles: [".mat-form-field{width:320px}.fill-remaining-space{-webkit-box-flex:1;flex:1 1 auto}.center{text-align:center}a{text-decoration:none;color:inherit}.lv-prop-label{color:rgba(0,0,0,.54)}.lv-html-text{position:relative;overflow:hidden}.kui-link{cursor:pointer;border-bottom:2px solid rgba(0,105,92,.25)}.kui-link:hover{box-shadow:0 -10px 0 rgba(0,105,92,.25) inset}"]
}),
__metadata("design:paramtypes", [])
], TextValueAsStringComponent);
let TextValueAsXmlComponent = class TextValueAsXmlComponent {
constructor() {
}
set valueObject(value) {
this._xmlValueObj = value;
}
get valueObject() {
return this._xmlValueObj;
}
};
__decorate([
Input(),
__metadata("design:type", ReadTextValueAsXml),
__metadata("design:paramtypes", [ReadTextValueAsXml])
], TextValueAsXmlComponent.prototype, "valueObject", null);
TextValueAsXmlComponent = __decorate([
Component({
selector: 'kui-text-value-as-xml',
template: "<span>{{valueObject.xml}}</span>",
styles: [""]
}),
__metadata("design:paramtypes", [])
], TextValueAsXmlComponent);
// TEMP CLASS DEFINITION BECAUSE MISSING IN KNORA/API LIB
// TODO: this class must be replaced with the new definition from the lib
class ReadTextFileValue extends ReadFileValue {
}
let TextfileValueComponent = class TextfileValueComponent {
constructor() { }
set valueObject(value) {
this._textfileValueObj = value;
}
get valueObject() {
return this._textfileValueObj;
}
};
__decorate([
Input(),
__metadata("design:type", ReadTextFileValue),
__metadata("design:paramtypes", [ReadTextFileValue])
], TextfileValueComponent.prototype, "valueObject", null);
TextfileValueComponent = __decorate([
Component({
selector: 'kui-textfile-value',
template: "<a target=\"_blank\" href=\"{{valueObject.fileUrl}}\">{{valueObject.filename}}</a>\n",
styles: [""]
}),
__metadata("design:paramtypes", [])
], TextfileValueComponent);
let UriValueComponent = class UriValueComponent {
constructor() { }
set valueObject(value) {
this.__uriValueObj = value;
}
get valueObject() {
return this.__uriValueObj;
}
ngOnChanges() {
if (this.label === undefined) {
this.displayString = this.__uriValueObj.uri;
}
else {
this.displayString = this.label;
}
}
};
__decorate([
Input(),
__metadata("design:type", ReadUriValue),
__metadata("design:paramtypes", [ReadUriValue])
], UriValueComponent.prototype, "valueObject", null);
__decorate([
Input(),
__metadata("design:type", String)
], UriValueComponent.prototype, "label", void 0);
UriValueComponent = __decorate([
Component({
selector: ' kui-uri-value',
template: "<a href=\"{{valueObject.uri}}\" target=\"_blank\" class=\"kui-link\">{{displayString}}</a>\n",
styles: [".mat-form-field{width:320px}.fill-remaining-space{-webkit-box-flex:1;flex:1 1 auto}.center{text-align:center}a{text-decoration:none;color:inherit}.kui-link{cursor:pointer;border-bottom:2px solid rgba(0,105,92,.25)}.lv-prop-label{color:rgba(0,0,0,.54)}.lv-html-text{position:relative;overflow:hidden}"]
}),
__metadata("design:paramtypes", [])
], UriValueComponent);
let GridViewComponent = class GridViewComponent {
constructor(_router) {
this._router = _router;
}
ngOnInit() {
}
/**
* Navigate to the resource viewer when clicking on one resource of the search result grid
* @param {string} id
*/
openResource(id) {
const url = '/resource/' + encodeURIComponent(id);
this._router.navigate([url]);
}
};
GridViewComponent.ctorParameters = () => [
{ type: Router }
];
__decorate([
Input(),
__metadata("design:type", Object)
], GridViewComponent.prototype, "result", void 0);
__decorate([
Input(),
__metadata("design:type", OntologyInformation)
], GridViewComponent.prototype, "ontologyInfo", void 0);
GridViewComponent = __decorate([
Component({
selector: 'kui-grid-view',
template: "<div>\n <!-- <kui-progress-indicator *ngIf=\"isLoading\" [color]=\"'#D88958'\"></kui-progress-indicator> -->\n\n <div fxLayout=\"row wrap\" fxLayout.xs=\"column\" fxLayoutGap=\"grid\">\n\n <div fxFlex.xs=\"100\" fxFlex.sm=\"50\" fxFlex.md=\"33.3\" fxFlex.lg=\"25\" fxFlex.xl=\"20\" *ngFor=\"let res of result\"\n class=\"gv-preview\">\n <mat-card class=\"link\" (click)=\"openResource(res.id)\">\n\n <mat-card-subtitle>{{res.entityInfo.classes[res.type].label}}</mat-card-subtitle>\n <mat-card-title>{{res.label}}</mat-card-title>\n\n\n <mat-card-content *ngFor=\"let prop of res.properties | kuiKey\">\n <div *ngFor=\"let val of prop.value | kuiKey\">\n <span class=\"lv-prop-label\">\n {{res.entityInfo.properties[val.value.property].label}}: \n </span>\n\n <div class=\"lv-html-text\">\n {{val.value.strval | kuiTruncate:['200', '...']}}\n </div>\n </div>\n </mat-card-content>\n\n </mat-card>\n </div>\n </div>\n\n\n</div>\n",
styles: [".mat-form-field{width:320px}.fill-remaining-space{-webkit-box-flex:1;flex:1 1 auto}.center{text-align:center}a{text-decoration:none;color:inherit}.kui-link{cursor:pointer;border-bottom:2px solid rgba(0,105,92,.25)}.lv-prop-label{color:rgba(0,0,0,.54)}.lv-html-text{position:relative;overflow:hidden}.gv-preview{margin:6px 0;padding:24px;word-wrap:break-word;border-radius:5px}.gv-preview .mat-card{height:180px;color:rgba(0,0,0,.81);overflow:hidden;padding-bottom:25px}.gv-preview .mat-card:hover{background:rgba(0,105,92,.39);color:#000}.gv-preview .mat-card:active{background:rgba(0,105,92,.61)}.gv-preview .mat-card .mat-card-title{font-siz