mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-14 13:33:03 +00:00
DS-4107 Retrieve and model metadata as a map
This commit is contained in:
@@ -7,10 +7,12 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let metadatum of metadata" class="metadata-row">
|
||||
<td>{{metadatum.key}}</td>
|
||||
<td>{{metadatum.value}}</td>
|
||||
<td>{{metadatum.language}}</td>
|
||||
<ng-container *ngFor="let entry of metadata | keyvalue">
|
||||
<tr *ngFor="let value of entry.value" class="metadata-row">
|
||||
<td>{{entry.key}}</td>
|
||||
<td>{{value.value}}</td>
|
||||
<td>{{value.language}}</td>
|
||||
</tr>
|
||||
</ng-container>
|
||||
</tbody>
|
||||
</table>
|
@@ -1,6 +1,6 @@
|
||||
import {Component, Input, OnInit} from '@angular/core';
|
||||
import {Item} from '../../../core/shared/item.model';
|
||||
import {Metadatum} from '../../../core/shared/metadatum.model';
|
||||
import {MetadataMap} from '../../../core/shared/metadata.interfaces';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-modify-item-overview',
|
||||
@@ -12,7 +12,7 @@ import {Metadatum} from '../../../core/shared/metadatum.model';
|
||||
export class ModifyItemOverviewComponent implements OnInit {
|
||||
|
||||
@Input() item: Item;
|
||||
metadata: Metadatum[];
|
||||
metadata: MetadataMap;
|
||||
|
||||
ngOnInit(): void {
|
||||
this.metadata = this.item.metadata;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<ds-metadata-field-wrapper [label]="label | translate">
|
||||
<a *ngFor="let metadatum of values; let last=last;" [href]="metadatum.value">
|
||||
{{ linktext || metadatum.value }}<span *ngIf="!last" [innerHTML]="separator"></span>
|
||||
<a *ngFor="let value of values; let last=last;" [href]="value.value">
|
||||
{{ linktext || value.value }}<span *ngIf="!last" [innerHTML]="separator"></span>
|
||||
</a>
|
||||
</ds-metadata-field-wrapper>
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
|
||||
import { MetadataValuesComponent } from '../metadata-values/metadata-values.component';
|
||||
import { MetadataValue } from '../../../core/shared/metadata.interfaces';
|
||||
|
||||
/**
|
||||
* This component renders the configured 'values' into the ds-metadata-field-wrapper component as a link.
|
||||
@@ -18,7 +19,7 @@ export class MetadataUriValuesComponent extends MetadataValuesComponent {
|
||||
|
||||
@Input() linktext: any;
|
||||
|
||||
@Input() values: any;
|
||||
@Input() values: MetadataValue[];
|
||||
|
||||
@Input() separator: string;
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<ds-metadata-field-wrapper [label]="label | translate">
|
||||
<span *ngFor="let metadatum of values; let last=last;">
|
||||
{{metadatum.value}}<span *ngIf="!last" [innerHTML]="separator"></span>
|
||||
<span *ngFor="let value of values; let last=last;">
|
||||
{{value.value}}<span *ngIf="!last" [innerHTML]="separator"></span>
|
||||
</span>
|
||||
</ds-metadata-field-wrapper>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { Metadatum } from '../../../core/shared/metadatum.model';
|
||||
import { MetadataValue } from '../../../core/shared/metadata.interfaces';
|
||||
|
||||
/**
|
||||
* This component renders the configured 'values' into the ds-metadata-field-wrapper component.
|
||||
@@ -12,7 +12,7 @@ import { Metadatum } from '../../../core/shared/metadatum.model';
|
||||
})
|
||||
export class MetadataValuesComponent {
|
||||
|
||||
@Input() values: Metadatum[];
|
||||
@Input() values: MetadataValue[];
|
||||
|
||||
@Input() separator: string;
|
||||
|
||||
|
@@ -17,7 +17,7 @@
|
||||
|
||||
|
||||
<dt class="col-md-4">{{"item.page.filesection.description" | translate}}</dt>
|
||||
<dd class="col-md-8">{{file.findMetadata("dc.description")}}</dd>
|
||||
<dd class="col-md-8">{{file.firstMetadataValue("dc.description")}}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
|
@@ -9,11 +9,13 @@
|
||||
</div>
|
||||
<table class="table table-responsive table-striped">
|
||||
<tbody>
|
||||
<tr *ngFor="let metadatum of (metadata$ | async)">
|
||||
<td>{{metadatum.key}}</td>
|
||||
<td>{{metadatum.value}}</td>
|
||||
<td>{{metadatum.language}}</td>
|
||||
<ng-container *ngFor="let entry of (metadata$ | async) | keyvalue">
|
||||
<tr *ngFor="let value of entry.value">
|
||||
<td>{{entry.key}}</td>
|
||||
<td>{{value.value}}</td>
|
||||
<td>{{value.language}}</td>
|
||||
</tr>
|
||||
</ng-container>
|
||||
</tbody>
|
||||
</table>
|
||||
<ds-item-page-full-file-section [item]="item"></ds-item-page-full-file-section>
|
||||
|
@@ -6,7 +6,7 @@ import { ActivatedRoute } from '@angular/router';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { ItemPageComponent } from '../simple/item-page.component';
|
||||
import { Metadatum } from '../../core/shared/metadatum.model';
|
||||
import { MetadataMap } from '../../core/shared/metadata.interfaces';
|
||||
import { ItemDataService } from '../../core/data/item-data.service';
|
||||
|
||||
import { RemoteData } from '../../core/data/remote-data';
|
||||
@@ -34,7 +34,7 @@ export class FullItemPageComponent extends ItemPageComponent implements OnInit {
|
||||
|
||||
itemRD$: Observable<RemoteData<Item>>;
|
||||
|
||||
metadata$: Observable<Metadatum[]>;
|
||||
metadata$: Observable<MetadataMap>;
|
||||
|
||||
constructor(route: ActivatedRoute, items: ItemDataService, metadataService: MetadataService) {
|
||||
super(route, items, metadataService);
|
||||
|
@@ -1,3 +1,3 @@
|
||||
<div class="item-page-specific-field">
|
||||
<ds-metadata-values [values]="item?.filterMetadata(fields)" [separator]="separator" [label]="label"></ds-metadata-values>
|
||||
<ds-metadata-values [values]="item?.allMetadata(fields)" [separator]="separator" [label]="label"></ds-metadata-values>
|
||||
</div>
|
||||
|
@@ -1,3 +1,3 @@
|
||||
<h2 class="item-page-title-field">
|
||||
<ds-metadata-values [values]="item?.filterMetadata(fields)"></ds-metadata-values>
|
||||
<ds-metadata-values [values]="item?.allMetadata(fields)"></ds-metadata-values>
|
||||
</h2>
|
||||
|
@@ -1,3 +1,3 @@
|
||||
<div class="item-page-specific-field">
|
||||
<ds-metadata-uri-values [values]="item?.filterMetadata(fields)" [separator]="separator" [label]="label"></ds-metadata-uri-values>
|
||||
<ds-metadata-uri-values [values]="item?.allMetadata(fields)" [separator]="separator" [label]="label"></ds-metadata-uri-values>
|
||||
</div>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { autoserialize } from 'cerialize';
|
||||
import { Metadatum } from '../core/shared/metadatum.model';
|
||||
import { MetadataMap } from '../core/shared/metadata.interfaces';
|
||||
import { ListableObject } from '../shared/object-collection/shared/listable-object.model';
|
||||
|
||||
/**
|
||||
@@ -16,6 +16,6 @@ export class NormalizedSearchResult implements ListableObject {
|
||||
* The metadata that was used to find this item, hithighlighted
|
||||
*/
|
||||
@autoserialize
|
||||
hitHighlights: Metadatum[];
|
||||
hitHighlights: MetadataMap;
|
||||
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { DSpaceObject } from '../core/shared/dspace-object.model';
|
||||
import { Metadatum } from '../core/shared/metadatum.model';
|
||||
import { MetadataMap } from '../core/shared/metadata.interfaces';
|
||||
import { ListableObject } from '../shared/object-collection/shared/listable-object.model';
|
||||
|
||||
/**
|
||||
@@ -14,6 +14,6 @@ export class SearchResult<T extends DSpaceObject> implements ListableObject {
|
||||
/**
|
||||
* The metadata that was used to find this item, hithighlighted
|
||||
*/
|
||||
hitHighlights: Metadatum[];
|
||||
hitHighlights: MetadataMap;
|
||||
|
||||
}
|
||||
|
@@ -38,8 +38,8 @@ import { DSpaceObject } from '../shared/dspace-object.model';
|
||||
export class BrowseService {
|
||||
protected linkPath = 'browses';
|
||||
|
||||
private static toSearchKeyArray(metadatumKey: string): string[] {
|
||||
const keyParts = metadatumKey.split('.');
|
||||
private static toSearchKeyArray(metadataKey: string): string[] {
|
||||
const keyParts = metadataKey.split('.');
|
||||
const searchFor = [];
|
||||
searchFor.push('*');
|
||||
for (let i = 0; i < keyParts.length - 1; i++) {
|
||||
@@ -47,7 +47,7 @@ export class BrowseService {
|
||||
const nextPart = [...prevParts, '*'].join('.');
|
||||
searchFor.push(nextPart);
|
||||
}
|
||||
searchFor.push(metadatumKey);
|
||||
searchFor.push(metadataKey);
|
||||
return searchFor;
|
||||
}
|
||||
|
||||
@@ -179,8 +179,8 @@ export class BrowseService {
|
||||
return this.rdb.toRemoteDataObservable(requestEntry$, payload$);
|
||||
}
|
||||
|
||||
getBrowseURLFor(metadatumKey: string, linkPath: string): Observable<string> {
|
||||
const searchKeyArray = BrowseService.toSearchKeyArray(metadatumKey);
|
||||
getBrowseURLFor(metadataKey: string, linkPath: string): Observable<string> {
|
||||
const searchKeyArray = BrowseService.toSearchKeyArray(metadataKey);
|
||||
return this.getBrowseDefinitions().pipe(
|
||||
getRemoteDataPayload(),
|
||||
map((browseDefinitions: BrowseDefinition[]) => browseDefinitions
|
||||
@@ -191,7 +191,7 @@ export class BrowseService {
|
||||
),
|
||||
map((def: BrowseDefinition) => {
|
||||
if (isEmpty(def) || isEmpty(def._links) || isEmpty(def._links[linkPath])) {
|
||||
throw new Error(`A browse endpoint for ${linkPath} on ${metadatumKey} isn't configured`);
|
||||
throw new Error(`A browse endpoint for ${linkPath} on ${metadataKey} isn't configured`);
|
||||
} else {
|
||||
return def._links[linkPath];
|
||||
}
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import { autoserialize, autoserializeAs, deserialize, serialize } from 'cerialize';
|
||||
import { DSpaceObject } from '../../shared/dspace-object.model';
|
||||
|
||||
import { Metadatum } from '../../shared/metadatum.model';
|
||||
import { MetadataMap } from '../../shared/metadata.interfaces';
|
||||
import { ResourceType } from '../../shared/resource-type';
|
||||
import { mapsTo } from '../builders/build-decorators';
|
||||
import { NormalizedObject } from './normalized-object.model';
|
||||
@@ -46,10 +45,10 @@ export class NormalizedDSpaceObject extends NormalizedObject {
|
||||
type: ResourceType;
|
||||
|
||||
/**
|
||||
* An array containing all metadata of this DSpaceObject
|
||||
* All metadata of this DSpaceObject
|
||||
*/
|
||||
@autoserializeAs(Metadatum)
|
||||
metadata: Metadatum[];
|
||||
@autoserialize
|
||||
metadata: MetadataMap;
|
||||
|
||||
/**
|
||||
* An array of DSpaceObjects that are direct parents of this DSpaceObject
|
||||
|
@@ -7,7 +7,7 @@ import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.
|
||||
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
||||
import { hasValue } from '../../shared/empty.util';
|
||||
import { SearchQueryResponse } from '../../+search-page/search-service/search-query-response.model';
|
||||
import { Metadatum } from '../shared/metadatum.model';
|
||||
import { MetadataMap, MetadataValue } from '../shared/metadata.interfaces';
|
||||
|
||||
@Injectable()
|
||||
export class SearchResponseParsingService implements ResponseParsingService {
|
||||
@@ -16,17 +16,17 @@ export class SearchResponseParsingService implements ResponseParsingService {
|
||||
|
||||
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
|
||||
const payload = data.payload._embedded.searchResult;
|
||||
const hitHighlights = payload._embedded.objects
|
||||
const hitHighlights: MetadataMap[] = payload._embedded.objects
|
||||
.map((object) => object.hitHighlights)
|
||||
.map((hhObject) => {
|
||||
const mdMap: MetadataMap = {};
|
||||
if (hhObject) {
|
||||
return Object.keys(hhObject).map((key) => Object.assign(new Metadatum(), {
|
||||
key: key,
|
||||
value: hhObject[key].join('...')
|
||||
}))
|
||||
} else {
|
||||
return [];
|
||||
for (const key of Object.keys(hhObject)) {
|
||||
const value: MetadataValue = { value: hhObject[key].join('...'), language: null };
|
||||
mdMap[key] = [ value ];
|
||||
}
|
||||
}
|
||||
return mdMap;
|
||||
});
|
||||
|
||||
const dsoSelfLinks = payload._embedded.objects
|
||||
|
@@ -91,9 +91,9 @@ export class DSpaceRESTv2Service {
|
||||
const form: FormData = new FormData();
|
||||
form.append('name', dso.name);
|
||||
if (dso.metadata) {
|
||||
for (const i of Object.keys(dso.metadata)) {
|
||||
if (isNotEmpty(dso.metadata[i].value)) {
|
||||
form.append(dso.metadata[i].key, dso.metadata[i].value);
|
||||
for (const key of Object.keys(dso.metadata)) {
|
||||
for (const value of dso.allMetadataValues(key)) {
|
||||
form.append(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -294,6 +294,10 @@ export class MetadataService {
|
||||
}
|
||||
}
|
||||
|
||||
private hasType(value: string): boolean {
|
||||
return this.currentObject.value.hasMetadata('dc.type', { value: value, ignoreCase: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this._item is a dissertation
|
||||
*
|
||||
@@ -301,14 +305,7 @@ export class MetadataService {
|
||||
* true if this._item has a dc.type equal to 'Thesis'
|
||||
*/
|
||||
private isDissertation(): boolean {
|
||||
let isDissertation = false;
|
||||
for (const metadatum of this.currentObject.value.metadata) {
|
||||
if (metadatum.key === 'dc.type') {
|
||||
isDissertation = metadatum.value.toLowerCase() === 'thesis';
|
||||
break;
|
||||
}
|
||||
}
|
||||
return isDissertation;
|
||||
return this.hasType('thesis');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -318,40 +315,15 @@ export class MetadataService {
|
||||
* true if this._item has a dc.type equal to 'Technical Report'
|
||||
*/
|
||||
private isTechReport(): boolean {
|
||||
let isTechReport = false;
|
||||
for (const metadatum of this.currentObject.value.metadata) {
|
||||
if (metadatum.key === 'dc.type') {
|
||||
isTechReport = metadatum.value.toLowerCase() === 'technical report';
|
||||
break;
|
||||
}
|
||||
}
|
||||
return isTechReport;
|
||||
return this.hasType('technical report');
|
||||
}
|
||||
|
||||
private getMetaTagValue(key: string): string {
|
||||
let value: string;
|
||||
for (const metadatum of this.currentObject.value.metadata) {
|
||||
if (metadatum.key === key) {
|
||||
value = metadatum.value;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
return this.currentObject.value.firstMetadataValue(key);
|
||||
}
|
||||
|
||||
private getFirstMetaTagValue(keys: string[]): string {
|
||||
let value: string;
|
||||
for (const metadatum of this.currentObject.value.metadata) {
|
||||
for (const key of keys) {
|
||||
if (key === metadatum.key) {
|
||||
value = metadatum.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (value !== undefined) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
return this.currentObject.value.firstMetadataValue(keys);
|
||||
}
|
||||
|
||||
private getMetaTagValuesAndCombine(key: string): string {
|
||||
@@ -359,15 +331,7 @@ export class MetadataService {
|
||||
}
|
||||
|
||||
private getMetaTagValues(keys: string[]): string[] {
|
||||
const values: string[] = [];
|
||||
for (const metadatum of this.currentObject.value.metadata) {
|
||||
for (const key of keys) {
|
||||
if (key === metadatum.key) {
|
||||
values.push(metadatum.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return values;
|
||||
return this.currentObject.value.allMetadataValues(keys);
|
||||
}
|
||||
|
||||
private addMetaTag(property: string, content: string): void {
|
||||
|
@@ -16,7 +16,7 @@ export class Collection extends DSpaceObject {
|
||||
* Corresponds to the metadata field dc.description
|
||||
*/
|
||||
get introductoryText(): string {
|
||||
return this.findMetadata('dc.description');
|
||||
return this.firstMetadataValue('dc.description');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -24,7 +24,7 @@ export class Collection extends DSpaceObject {
|
||||
* Corresponds to the metadata field dc.description.abstract
|
||||
*/
|
||||
get shortDescription(): string {
|
||||
return this.findMetadata('dc.description.abstract');
|
||||
return this.firstMetadataValue('dc.description.abstract');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,7 +32,7 @@ export class Collection extends DSpaceObject {
|
||||
* Corresponds to the metadata field dc.rights
|
||||
*/
|
||||
get copyrightText(): string {
|
||||
return this.findMetadata('dc.rights');
|
||||
return this.firstMetadataValue('dc.rights');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -40,7 +40,7 @@ export class Collection extends DSpaceObject {
|
||||
* Corresponds to the metadata field dc.rights.license
|
||||
*/
|
||||
get license(): string {
|
||||
return this.findMetadata('dc.rights.license');
|
||||
return this.firstMetadataValue('dc.rights.license');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,7 +48,7 @@ export class Collection extends DSpaceObject {
|
||||
* Corresponds to the metadata field dc.description.tableofcontents
|
||||
*/
|
||||
get sidebarText(): string {
|
||||
return this.findMetadata('dc.description.tableofcontents');
|
||||
return this.firstMetadataValue('dc.description.tableofcontents');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -17,7 +17,7 @@ export class Community extends DSpaceObject {
|
||||
* Corresponds to the metadata field dc.description
|
||||
*/
|
||||
get introductoryText(): string {
|
||||
return this.findMetadata('dc.description');
|
||||
return this.firstMetadataValue('dc.description');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -25,7 +25,7 @@ export class Community extends DSpaceObject {
|
||||
* Corresponds to the metadata field dc.description.abstract
|
||||
*/
|
||||
get shortDescription(): string {
|
||||
return this.findMetadata('dc.description.abstract');
|
||||
return this.firstMetadataValue('dc.description.abstract');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -33,7 +33,7 @@ export class Community extends DSpaceObject {
|
||||
* Corresponds to the metadata field dc.rights
|
||||
*/
|
||||
get copyrightText(): string {
|
||||
return this.findMetadata('dc.rights');
|
||||
return this.firstMetadataValue('dc.rights');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,7 +41,7 @@ export class Community extends DSpaceObject {
|
||||
* Corresponds to the metadata field dc.description.tableofcontents
|
||||
*/
|
||||
get sidebarText(): string {
|
||||
return this.findMetadata('dc.description.tableofcontents');
|
||||
return this.firstMetadataValue('dc.description.tableofcontents');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { Metadatum } from './metadatum.model'
|
||||
import { isEmpty, isNotEmpty } from '../../shared/empty.util';
|
||||
import { MetadataMap, MetadataValue, MetadataValueFilter } from './metadata.interfaces';
|
||||
import { Metadata } from './metadata.model';
|
||||
import { CacheableObject } from '../cache/object-cache.reducer';
|
||||
import { RemoteData } from '../data/remote-data';
|
||||
import { ResourceType } from './resource-type';
|
||||
@@ -35,14 +35,14 @@ export class DSpaceObject implements CacheableObject, ListableObject {
|
||||
* The name for this DSpaceObject
|
||||
*/
|
||||
get name(): string {
|
||||
return this.findMetadata('dc.title');
|
||||
return this.firstMetadataValue('dc.title');
|
||||
}
|
||||
|
||||
/**
|
||||
* An array containing all metadata of this DSpaceObject
|
||||
* All metadata of this DSpaceObject
|
||||
*/
|
||||
@autoserialize
|
||||
metadata: Metadatum[] = [];
|
||||
metadata: MetadataMap;
|
||||
|
||||
/**
|
||||
* An array of DSpaceObjects that are direct parents of this DSpaceObject
|
||||
@@ -54,42 +54,29 @@ export class DSpaceObject implements CacheableObject, ListableObject {
|
||||
*/
|
||||
owner: Observable<RemoteData<DSpaceObject>>;
|
||||
|
||||
/**
|
||||
* Find a metadata field by key and language
|
||||
*
|
||||
* This method returns the value of the first element
|
||||
* in the metadata array that matches the provided
|
||||
* key and language
|
||||
*
|
||||
* @param key
|
||||
* @param language
|
||||
* @return string
|
||||
*/
|
||||
findMetadata(key: string, language?: string): string {
|
||||
const metadatum = this.metadata.find((m: Metadatum) => {
|
||||
return m.key === key && (isEmpty(language) || m.language === language)
|
||||
});
|
||||
if (isNotEmpty(metadatum)) {
|
||||
return metadatum.value;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
/** Gets all matching metadata in this DSpaceObject. See `Metadata.all` for more information. */
|
||||
allMetadata(keyOrKeys: string | string[], valueFilter?: MetadataValueFilter): MetadataValue[] {
|
||||
return Metadata.all(this.metadata, keyOrKeys, valueFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find metadata by an array of keys
|
||||
*
|
||||
* This method returns the values of the element
|
||||
* in the metadata array that match the provided
|
||||
* key(s)
|
||||
*
|
||||
* @param key(s)
|
||||
* @return Array<Metadatum>
|
||||
*/
|
||||
filterMetadata(keys: string[]): Metadatum[] {
|
||||
return this.metadata.filter((metadatum: Metadatum) => {
|
||||
return keys.some((key) => key === metadatum.key);
|
||||
});
|
||||
/** Like `allMetadata`, but only returns string values. */
|
||||
allMetadataValues(keyOrKeys: string | string[], valueFilter?: MetadataValueFilter): string[] {
|
||||
return Metadata.allValues(this.metadata, keyOrKeys, valueFilter);
|
||||
}
|
||||
|
||||
/** Gets the first matching metadata in this DSpaceObject, or `undefined`. */
|
||||
firstMetadata(keyOrKeys: string | string[], valueFilter?: MetadataValueFilter): MetadataValue {
|
||||
return Metadata.first(this.metadata, keyOrKeys, valueFilter);
|
||||
}
|
||||
|
||||
/** Like `firstMetadata`, but only returns a string value, or `undefined`. */
|
||||
firstMetadataValue(keyOrKeys: string | string[], valueFilter?: MetadataValueFilter): string {
|
||||
return Metadata.firstValue(this.metadata, keyOrKeys, valueFilter);
|
||||
}
|
||||
|
||||
/** Checks for matching metadata in this DSpaceObject. */
|
||||
hasMetadata(keyOrKeys: string | string[], valueFilter?: MetadataValueFilter): boolean {
|
||||
return Metadata.has(this.metadata, keyOrKeys, valueFilter);
|
||||
}
|
||||
|
||||
}
|
||||
|
30
src/app/core/shared/metadata.interfaces.ts
Normal file
30
src/app/core/shared/metadata.interfaces.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/** A map of metadata keys to an ordered list of MetadataValue objects. */
|
||||
export interface MetadataMap {
|
||||
[ key: string ]: MetadataValue[];
|
||||
}
|
||||
|
||||
/** A single metadata value and its properties. */
|
||||
export interface MetadataValue {
|
||||
|
||||
/** The language. */
|
||||
language: string;
|
||||
|
||||
/** The string value. */
|
||||
value: string;
|
||||
}
|
||||
|
||||
/** Constraints for matching metadata values. */
|
||||
export interface MetadataValueFilter {
|
||||
|
||||
/** The language constraint. */
|
||||
language?: string;
|
||||
|
||||
/** The value constraint. */
|
||||
value?: string;
|
||||
|
||||
/** Whether the value constraint should match without regard to case. */
|
||||
ignoreCase?: boolean;
|
||||
|
||||
/** Whether the value constraint should match as a substring. */
|
||||
substring?: boolean;
|
||||
}
|
119
src/app/core/shared/metadata.model.ts
Normal file
119
src/app/core/shared/metadata.model.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import { isEmpty } from '../../shared/empty.util';
|
||||
import { MetadataMap, MetadataValue, MetadataValueFilter } from './metadata.interfaces';
|
||||
|
||||
/**
|
||||
* Static utility methods for working with DSpace metadata.
|
||||
*/
|
||||
export class Metadata {
|
||||
|
||||
/**
|
||||
* Gets all matching metadata.
|
||||
*
|
||||
* @param {MetadataMap|MetadataMap[]} mapOrMaps The source map(s). Values will only be returned from one map --
|
||||
* the first with at least one match.
|
||||
* @param {string|string[]} keyOrKeys The metadata key(s) in scope. Wildcards are supported, so `'*'` will
|
||||
* match all keys, `'dc.date.*'` will match all qualified dc dates, and so on. Exact keys will be evaluated
|
||||
* (and matches returned) in the order they are given in the parameter. When multiple keys match a wildcard,
|
||||
* they are evaluated in the order they are stored in the map (alphanumeric if obtained from the REST api).
|
||||
* If duplicate or overlapping keys are specified, the first one takes precedence. For example, specifying
|
||||
* `['dc.date', 'dc.*', '*']` will cause any `dc.date` values to be evaluated (and returned, if matched)
|
||||
* first, followed by any other `dc` metadata values, followed by any other (non-dc) metadata values.
|
||||
* @param {MetadataValueFilter} filter The value filter to use.
|
||||
* @returns {MetadataValue[]} the matching values or an empty array.
|
||||
*/
|
||||
public static all(mapOrMaps: MetadataMap | MetadataMap[], keyOrKeys: string | string[],
|
||||
filter?: MetadataValueFilter): MetadataValue[] {
|
||||
const mdMaps: MetadataMap[] = mapOrMaps instanceof Array ? mapOrMaps : [ mapOrMaps ];
|
||||
const matches: MetadataValue[] = [];
|
||||
for (const mdMap of mdMaps) {
|
||||
for (const mdKey of Metadata.resolveKeys(mdMap, keyOrKeys)) {
|
||||
const candidates = mdMap[mdKey];
|
||||
if (candidates) {
|
||||
for (const candidate of candidates) {
|
||||
if (Metadata.valueMatches(candidate, filter)) {
|
||||
matches.push(candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isEmpty(matches)) {
|
||||
return matches;
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
/** Like `all`, but only returns string values. */
|
||||
public static allValues(mapOrMaps: MetadataMap | MetadataMap[], keyOrKeys: string | string[],
|
||||
filter?: MetadataValueFilter): string[] {
|
||||
return Metadata.all(mapOrMaps, keyOrKeys, filter).map((mdValue) => mdValue.value);
|
||||
}
|
||||
|
||||
/** Gets the first matching MetadataValue object in a map, or `undefined`. */
|
||||
public static first(mdMapOrMaps: MetadataMap | MetadataMap[], keyOrKeys: string | string[],
|
||||
filter?: MetadataValueFilter): MetadataValue {
|
||||
const mdMaps: MetadataMap[] = mdMapOrMaps instanceof Array ? mdMapOrMaps : [ mdMapOrMaps ];
|
||||
for (const mdMap of mdMaps) {
|
||||
for (const key of Metadata.resolveKeys(mdMap, keyOrKeys)) {
|
||||
const values: MetadataValue[] = mdMap[key];
|
||||
if (values) {
|
||||
return values.find((value: MetadataValue) => Metadata.valueMatches(value, filter));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Like `first`, but only returns a string value, or `undefined`. */
|
||||
public static firstValue(mdMapOrMaps: MetadataMap | MetadataMap[], keyOrKeys: string | string[],
|
||||
filter?: MetadataValueFilter): string {
|
||||
const value = Metadata.first(mdMapOrMaps, keyOrKeys, filter);
|
||||
return value === undefined ? undefined : value.value;
|
||||
}
|
||||
|
||||
/** Checks the given map for a matching value. */
|
||||
public static has(mdMapOrMaps: MetadataMap | MetadataMap[], keyOrKeys: string | string[],
|
||||
filter?: MetadataValueFilter): boolean {
|
||||
return Metadata.first(mdMapOrMaps, keyOrKeys, filter) !== undefined;
|
||||
}
|
||||
|
||||
/** Checks if a value matches a filter. */
|
||||
public static valueMatches(mdValue: MetadataValue, filter: MetadataValueFilter) {
|
||||
if (!filter) {
|
||||
return true;
|
||||
} else if (filter.language && filter.language !== mdValue.language) {
|
||||
return false;
|
||||
} else if (filter.value) {
|
||||
let fValue = filter.value;
|
||||
let mValue = mdValue.value;
|
||||
if (filter.ignoreCase) {
|
||||
fValue = filter.value.toLowerCase();
|
||||
mValue = mdValue.value.toLowerCase();
|
||||
}
|
||||
if (filter.substring) {
|
||||
return mValue.includes(fValue);
|
||||
} else {
|
||||
return mValue === fValue;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Gets the list of keys in the map limited by, and in the order given by `keyOrKeys` */
|
||||
private static resolveKeys(mdMap: MetadataMap, keyOrKeys: string | string[]): string[] {
|
||||
const inputKeys: string[] = keyOrKeys instanceof Array ? keyOrKeys : [ keyOrKeys ];
|
||||
const outputKeys: string[] = [];
|
||||
for (const inputKey of inputKeys) {
|
||||
if (inputKey.includes('*')) {
|
||||
const inputKeyRegex = new RegExp('^' + inputKey.replace('.', '\.').replace('*', '.*') + '$');
|
||||
for (const mapKey of Object.keys(mdMap)) {
|
||||
if (!outputKeys.includes(mapKey) && inputKeyRegex.test(mapKey)) {
|
||||
outputKeys.push(mapKey);
|
||||
}
|
||||
}
|
||||
} else if (mdMap.hasOwnProperty(inputKey) && !outputKeys.includes(inputKey)) {
|
||||
outputKeys.push(inputKey);
|
||||
}
|
||||
}
|
||||
return outputKeys;
|
||||
}
|
||||
}
|
@@ -1,23 +0,0 @@
|
||||
import { autoserialize } from 'cerialize';
|
||||
|
||||
export class Metadatum {
|
||||
|
||||
/**
|
||||
* The metadata field of this Metadatum
|
||||
*/
|
||||
@autoserialize
|
||||
key: string;
|
||||
|
||||
/**
|
||||
* The language of this Metadatum
|
||||
*/
|
||||
@autoserialize
|
||||
language: string;
|
||||
|
||||
/**
|
||||
* The value of this Metadatum
|
||||
*/
|
||||
@autoserialize
|
||||
value: string;
|
||||
|
||||
}
|
@@ -8,6 +8,7 @@ import { FormGroup } from '@angular/forms';
|
||||
import { DynamicFormControlModel } from '@ng-dynamic-forms/core/src/model/dynamic-form-control.model';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||
import { MetadataMap, MetadataValue } from '../../../core/shared/metadata.interfaces';
|
||||
import { isNotEmpty } from '../../empty.util';
|
||||
import { ResourceType } from '../../../core/shared/resource-type';
|
||||
|
||||
@@ -64,7 +65,7 @@ export class ComColFormComponent<T extends DSpaceObject> implements OnInit {
|
||||
ngOnInit(): void {
|
||||
this.formModel.forEach(
|
||||
(fieldModel: DynamicInputModel) => {
|
||||
fieldModel.value = this.dso.findMetadata(fieldModel.name);
|
||||
fieldModel.value = this.dso.firstMetadataValue(fieldModel.name);
|
||||
}
|
||||
);
|
||||
this.formGroup = this.formService.createFormGroup(this.formModel);
|
||||
@@ -77,20 +78,24 @@ export class ComColFormComponent<T extends DSpaceObject> implements OnInit {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks which new fields where added and sends the updated version of the DSO to the parent component
|
||||
* Checks which new fields were added and sends the updated version of the DSO to the parent component
|
||||
*/
|
||||
onSubmit() {
|
||||
const metadata = this.formModel.map(
|
||||
(fieldModel: DynamicInputModel) => {
|
||||
return { key: fieldModel.name, value: fieldModel.value }
|
||||
const formMetadata = new Object() as MetadataMap;
|
||||
this.formModel.forEach((fieldModel: DynamicInputModel) => {
|
||||
const value: MetadataValue = { value: fieldModel.value as string, language: null };
|
||||
if (formMetadata.hasOwnProperty(fieldModel.name)) {
|
||||
formMetadata[fieldModel.name].push(value);
|
||||
} else {
|
||||
formMetadata[fieldModel.name] = [ value ];
|
||||
}
|
||||
);
|
||||
const filteredOldMetadata = this.dso.metadata.filter((filter) => !metadata.map((md) => md.key).includes(filter.key));
|
||||
const filteredNewMetadata = metadata.filter((md) => isNotEmpty(md.value));
|
||||
});
|
||||
|
||||
const newMetadata = [...filteredOldMetadata, ...filteredNewMetadata];
|
||||
const updatedDSO = Object.assign({}, this.dso, {
|
||||
metadata: newMetadata,
|
||||
metadata: {
|
||||
...this.dso.metadata,
|
||||
...formMetadata
|
||||
},
|
||||
type: ResourceType.Community
|
||||
});
|
||||
this.submitForm.emit(updatedDSO);
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { ListableObject } from '../listable-object.model';
|
||||
import { hasValue } from '../../../empty.util';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-abstract-object-element',
|
||||
@@ -11,8 +10,4 @@ export class AbstractListableElementComponent <T extends ListableObject> {
|
||||
public constructor(@Inject('objectElementProvider') public listableObject: ListableObject) {
|
||||
this.object = listableObject as T;
|
||||
}
|
||||
|
||||
hasValue(data) {
|
||||
return hasValue(data);
|
||||
}
|
||||
}
|
||||
|
@@ -5,19 +5,19 @@
|
||||
</ds-grid-thumbnail>
|
||||
</a>
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">{{object.findMetadata('dc.title')}}</h4>
|
||||
<h4 class="card-title">{{object.firstMetadataValue('dc.title')}}</h4>
|
||||
|
||||
<ds-truncatable-part [id]="object.id" [minLines]="2">
|
||||
<p *ngIf="object.filterMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']).length > 0" class="item-authors card-text text-muted">
|
||||
<span *ngFor="let authorMd of object.filterMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']); let last=last;">{{authorMd.value}}
|
||||
<p *ngIf="object.hasMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*'])" class="item-authors card-text text-muted">
|
||||
<span *ngFor="let author of object.allMetadataValues(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']); let last=last;">{{author}}
|
||||
<span *ngIf="!last">; </span>
|
||||
</span>
|
||||
<span *ngIf="hasValue(object.findMetadata('dc.date.issued'))" class="item-date">{{object.findMetadata("dc.date.issued")}}</span>
|
||||
<span *ngIf="object.hasMetadata('dc.date.issued')" class="item-date">{{object.firstMetadataValue("dc.date.issued")}}</span>
|
||||
</p>
|
||||
</ds-truncatable-part>
|
||||
|
||||
<ds-truncatable-part [id]="object.id" [minLines]="5">
|
||||
<p *ngIf="object.findMetadata('dc.description.abstract')" class="item-abstract card-text">{{object.findMetadata("dc.description.abstract") }}</p>
|
||||
<p *ngIf="object.hasMetadata('dc.description.abstract')" class="item-abstract card-text">{{object.firstMetadataValue("dc.description.abstract")}}</p>
|
||||
</ds-truncatable-part>
|
||||
|
||||
<div class="text-center pt-2">
|
||||
|
@@ -8,20 +8,20 @@
|
||||
</a>
|
||||
<div class="card-body">
|
||||
<ds-truncatable-part [fixedHeight]="true" [id]="dso.id" [minLines]="3" type="h4">
|
||||
<h4 class="card-title" [innerHTML]="dso.findMetadata('dc.title')"></h4>
|
||||
<h4 class="card-title" [innerHTML]="dso.firstMetadataValue('dc.title')"></h4>
|
||||
</ds-truncatable-part>
|
||||
<p *ngIf="dso.filterMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']).length > 0"
|
||||
<p *ngIf="dso.hasMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*'])"
|
||||
class="item-authors card-text text-muted">
|
||||
<ds-truncatable-part [fixedHeight]="true" [id]="dso.id" [minLines]="1">
|
||||
<span *ngIf="hasValue(dso.findMetadata('dc.date.issued'))" class="item-date">{{dso.findMetadata("dc.date.issued")}}</span>
|
||||
<span *ngFor="let authorMd of dso.filterMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']);">,
|
||||
<span [innerHTML]="authorMd.value"></span>
|
||||
<span *ngIf="dso.hasMetadata('dc.date.issued')" class="item-date">{{dso.firstMetadataValue('dc.date.issued')}}</span>
|
||||
<span *ngFor="let author of dso.allMetadataValues(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']);">,
|
||||
<span [innerHTML]="author"></span>
|
||||
</span>
|
||||
</ds-truncatable-part>
|
||||
</p>
|
||||
<p class="item-abstract card-text">
|
||||
<ds-truncatable-part [fixedHeight]="true" [id]="dso.id" [minLines]="3">
|
||||
<span [innerHTML]="getFirstValue('dc.description.abstract')"></span>
|
||||
<span [innerHTML]="firstMetadataValue('dc.description.abstract')"></span>
|
||||
</ds-truncatable-part>
|
||||
</p>
|
||||
<div class="text-center">
|
||||
|
@@ -2,12 +2,11 @@ import { Component, Inject } from '@angular/core';
|
||||
|
||||
import { SearchResult } from '../../../+search-page/search-result.model';
|
||||
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||
import { Metadatum } from '../../../core/shared/metadatum.model';
|
||||
import { isEmpty, hasNoValue, hasValue } from '../../empty.util';
|
||||
import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component';
|
||||
import { ListableObject } from '../../object-collection/shared/listable-object.model';
|
||||
import { TruncatableService } from '../../truncatable/truncatable.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Metadata } from '../../../core/shared/metadata.model';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-search-result-grid-element',
|
||||
@@ -22,39 +21,14 @@ export class SearchResultGridElementComponent<T extends SearchResult<K>, K exten
|
||||
this.dso = this.object.dspaceObject;
|
||||
}
|
||||
|
||||
getValues(keys: string[]): string[] {
|
||||
const results: string[] = new Array<string>();
|
||||
this.object.hitHighlights.forEach(
|
||||
(md: Metadatum) => {
|
||||
if (keys.indexOf(md.key) > -1) {
|
||||
results.push(md.value);
|
||||
}
|
||||
}
|
||||
);
|
||||
if (isEmpty(results)) {
|
||||
this.dso.filterMetadata(keys).forEach(
|
||||
(md: Metadatum) => {
|
||||
results.push(md.value);
|
||||
}
|
||||
);
|
||||
}
|
||||
return results;
|
||||
/** Gets all matching metadata string values from hitHighlights or dso metadata, preferring hitHighlights. */
|
||||
allMetadataValues(keyOrKeys: string | string[]): string[] {
|
||||
return Metadata.allValues([this.object.hitHighlights, this.dso.metadata], keyOrKeys);
|
||||
}
|
||||
|
||||
getFirstValue(key: string): string {
|
||||
let result: string;
|
||||
this.object.hitHighlights.some(
|
||||
(md: Metadatum) => {
|
||||
if (key === md.key) {
|
||||
result = md.value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
);
|
||||
if (hasNoValue(result)) {
|
||||
result = this.dso.findMetadata(key);
|
||||
}
|
||||
return result;
|
||||
/** Gets the first matching metadata string value from hitHighlights or dso metadata, preferring hitHighlights. */
|
||||
firstMetadataValue(keyOrKeys: string | string[]): string {
|
||||
return Metadata.firstValue([this.object.hitHighlights, this.dso.metadata], keyOrKeys);
|
||||
}
|
||||
|
||||
isCollapsed(): Observable<boolean> {
|
||||
|
@@ -1,23 +1,23 @@
|
||||
<ds-truncatable [id]="object.id">
|
||||
<a [routerLink]="['/items/' + object.id]" class="lead">
|
||||
{{object.findMetadata("dc.title")}}
|
||||
{{object.firstMetadataValue("dc.title")}}
|
||||
</a>
|
||||
<div>
|
||||
<ds-truncatable-part [id]="object.id" [minLines]="1">
|
||||
<span class="text-muted">
|
||||
<span *ngIf="object.filterMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']).length > 0"
|
||||
<span *ngIf="object.hasMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*'])"
|
||||
class="item-list-authors">
|
||||
<span *ngFor="let authorMd of object.filterMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']); let last=last;">{{authorMd.value}}
|
||||
<span *ngFor="let author of object.allMetadataValues(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']); let last=last;">{{author}}
|
||||
<span *ngIf="!last">; </span>
|
||||
</span>
|
||||
</span>
|
||||
(<span *ngIf="hasValue(object.findMetadata('dc.publisher'))" class="item-list-publisher">{{object.findMetadata("dc.publisher")}}, </span><span
|
||||
*ngIf="hasValue(object.findMetadata('dc.date.issued'))" class="item-list-date">{{object.findMetadata("dc.date.issued")}}</span>)
|
||||
(<span *ngIf="object.hasMetadata('dc.publisher')" class="item-list-publisher">{{object.firstMetadataValue("dc.publisher")}}, </span><span
|
||||
*ngIf="object.hasMetadata('dc.date.issued')" class="item-list-date">{{object.firstMetadataValue("dc.date.issued")}}</span>)
|
||||
</span>
|
||||
</ds-truncatable-part>
|
||||
<ds-truncatable-part [id]="object.id" [minLines]="3">
|
||||
<div *ngIf="object.findMetadata('dc.description.abstract')" class="item-list-abstract">
|
||||
{{object.findMetadata("dc.description.abstract")}}
|
||||
<div *ngIf="object.hasMetadata('dc.description.abstract')" class="item-list-abstract">
|
||||
{{object.firstMetadataValue("dc.description.abstract")}}
|
||||
</div>
|
||||
</ds-truncatable-part>
|
||||
</div>
|
||||
|
@@ -1,2 +1,2 @@
|
||||
<a [routerLink]="['/collections/' + dso.id]" class="lead" [innerHTML]="getFirstValue('dc.title')"></a>
|
||||
<div *ngIf="dso.shortDescription" class="text-muted abstract-text" [innerHTML]="getFirstValue('dc.description.abstract')"></div>
|
||||
<a [routerLink]="['/collections/' + dso.id]" class="lead" [innerHTML]="firstMetadataValue('dc.title')"></a>
|
||||
<div *ngIf="dso.shortDescription" class="text-muted abstract-text" [innerHTML]="firstMetadataValue('dc.description.abstract')"></div>
|
||||
|
@@ -1,2 +1,2 @@
|
||||
<a [routerLink]="['/communities/' + dso.id]" class="lead" [innerHTML]="getFirstValue('dc.title')"></a>
|
||||
<div *ngIf="dso.shortDescription" class="text-muted abstract-text" [innerHTML]="getFirstValue('dc.description.abstract')"></div>
|
||||
<a [routerLink]="['/communities/' + dso.id]" class="lead" [innerHTML]="firstMetadataValue('dc.title')"></a>
|
||||
<div *ngIf="dso.shortDescription" class="text-muted abstract-text" [innerHTML]="firstMetadataValue('dc.description.abstract')"></div>
|
||||
|
@@ -1,24 +1,24 @@
|
||||
<ds-truncatable [id]="dso.id">
|
||||
<a
|
||||
[routerLink]="['/items/' + dso.id]" class="lead"
|
||||
[innerHTML]="getFirstValue('dc.title')"></a>
|
||||
[innerHTML]="firstMetadataValue('dc.title')"></a>
|
||||
<span class="text-muted">
|
||||
<ds-truncatable-part [id]="dso.id" [minLines]="1">
|
||||
(<span *ngIf="dso.findMetadata('dc.publisher')" class="item-list-publisher"
|
||||
[innerHTML]="getFirstValue('dc.publisher') + ', '"></span><span
|
||||
*ngIf="hasValue(dso.findMetadata('dc.date.issued'))" class="item-list-date"
|
||||
[innerHTML]="getFirstValue('dc.date.issued')"></span>)
|
||||
<span *ngIf="dso.filterMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']).length > 0"
|
||||
(<span *ngIf="dso.hasMetadata('dc.publisher')" class="item-list-publisher"
|
||||
[innerHTML]="firstMetadataValue('dc.publisher') + ', '"></span><span
|
||||
*ngIf="dso.hasMetadata('dc.date.issued')" class="item-list-date"
|
||||
[innerHTML]="firstMetadataValue('dc.date.issued')"></span>)
|
||||
<span *ngIf="dso.hasMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*'])"
|
||||
class="item-list-authors">
|
||||
<span *ngFor="let author of getValues(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']); let last=last;">
|
||||
<span *ngFor="let author of allMetadataValues(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']); let last=last;">
|
||||
<span [innerHTML]="author"><span [innerHTML]="author"></span></span>
|
||||
</span>
|
||||
</span>
|
||||
</ds-truncatable-part>
|
||||
</span>
|
||||
<div *ngIf="dso.findMetadata('dc.description.abstract')" class="item-list-abstract">
|
||||
<div *ngIf="dso.hasMetadata('dc.description.abstract')" class="item-list-abstract">
|
||||
<ds-truncatable-part [id]="dso.id" [minLines]="3"><span
|
||||
[innerHTML]="getFirstValue('dc.description.abstract')"></span>
|
||||
[innerHTML]="firstMetadataValue('dc.description.abstract')"></span>
|
||||
</ds-truncatable-part>
|
||||
</div>
|
||||
</ds-truncatable>
|
@@ -3,11 +3,10 @@ import { Observable } from 'rxjs';
|
||||
|
||||
import { SearchResult } from '../../../+search-page/search-result.model';
|
||||
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||
import { Metadatum } from '../../../core/shared/metadatum.model';
|
||||
import { hasNoValue, isEmpty } from '../../empty.util';
|
||||
import { ListableObject } from '../../object-collection/shared/listable-object.model';
|
||||
import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component';
|
||||
import { TruncatableService } from '../../truncatable/truncatable.service';
|
||||
import { Metadata } from '../../../core/shared/metadata.model';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-search-result-list-element',
|
||||
@@ -22,39 +21,14 @@ export class SearchResultListElementComponent<T extends SearchResult<K>, K exten
|
||||
this.dso = this.object.dspaceObject;
|
||||
}
|
||||
|
||||
getValues(keys: string[]): string[] {
|
||||
const results: string[] = new Array<string>();
|
||||
this.object.hitHighlights.forEach(
|
||||
(md: Metadatum) => {
|
||||
if (keys.indexOf(md.key) > -1) {
|
||||
results.push(md.value);
|
||||
}
|
||||
}
|
||||
);
|
||||
if (isEmpty(results)) {
|
||||
this.dso.filterMetadata(keys).forEach(
|
||||
(md: Metadatum) => {
|
||||
results.push(md.value);
|
||||
}
|
||||
);
|
||||
}
|
||||
return results;
|
||||
/** Gets all matching metadata string values from hitHighlights or dso metadata, preferring hitHighlights. */
|
||||
allMetadataValues(keyOrKeys: string | string[]): string[] {
|
||||
return Metadata.allValues([this.object.hitHighlights, this.dso.metadata], keyOrKeys);
|
||||
}
|
||||
|
||||
getFirstValue(key: string): string {
|
||||
let result: string;
|
||||
this.object.hitHighlights.some(
|
||||
(md: Metadatum) => {
|
||||
if (key === md.key) {
|
||||
result = md.value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
);
|
||||
if (hasNoValue(result)) {
|
||||
result = this.dso.findMetadata(key);
|
||||
}
|
||||
return result;
|
||||
/** Gets the first matching metadata string value from hitHighlights or dso metadata, preferring hitHighlights. */
|
||||
firstMetadataValue(keyOrKeys: string | string[]): string {
|
||||
return Metadata.firstValue([this.object.hitHighlights, this.dso.metadata], keyOrKeys);
|
||||
}
|
||||
|
||||
isCollapsed(): Observable<boolean> {
|
||||
|
Reference in New Issue
Block a user